summaryrefslogtreecommitdiffstats
path: root/poi-examples
diff options
context:
space:
mode:
authorAndreas Beeker <kiwiwings@apache.org>2021-04-07 21:40:33 +0000
committerAndreas Beeker <kiwiwings@apache.org>2021-04-07 21:40:33 +0000
commitb6aee1ef6d3e92a28ffd4b5c03e677b63b43747f (patch)
treead9c7b312976c4ed113a7f3b5b4757bfe1b3eee6 /poi-examples
parent6458acb931a0cc17b2d5ed205a1b3fbbb78b9193 (diff)
downloadpoi-b6aee1ef6d3e92a28ffd4b5c03e677b63b43747f.tar.gz
poi-b6aee1ef6d3e92a28ffd4b5c03e677b63b43747f.zip
65206 - Migrate ant / maven to gradle build
compile / jar / test of mrJars don't include ants build.xml anymore rename directories to match project and maven artifact names refactor artifacts - so each project has one artifact replace static references in hssf/dev tests with junit5 constructs, which had problems in parallel tests increase gradle heap to 4gb because of OOM - maybe less would also work git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1888488 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'poi-examples')
-rw-r--r--poi-examples/build.gradle99
-rw-r--r--poi-examples/src/main/clojure/SpreadSheetDemo.clj36
-rw-r--r--poi-examples/src/main/groovy/SpreadSheetDemo.groovy108
-rw-r--r--poi-examples/src/main/groovy/build.gradle43
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/crypt/OOXMLPasswordsTry.java89
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hpsf/CopyCompare.java200
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hpsf/ModifyDocumentSummaryInformation.java159
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hpsf/ReadCustomPropertySets.java109
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hpsf/ReadTitle.java64
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hpsf/WriteAuthorAndTitle.java174
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hpsf/WriteTitle.java104
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hslf/ApacheconEU08.java460
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hslf/BulletsDemo.java60
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hslf/CreateHyperlink.java64
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hslf/DataExtraction.java148
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hslf/Graphics2DDemo.java82
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hslf/HeadersFootersDemo.java50
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hslf/Hyperlinks.java77
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hslf/SoundFinder.java69
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hslf/TableDemo.java132
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hsmf/Msg2txt.java158
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hssf/eventusermodel/XLS2CSVmra.java330
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/AddDimensionedImage.java23
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/Alignment.java72
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/BigExample.java169
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/Borders.java64
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/CellComments.java124
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/CellTypes.java46
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/CreateCells.java55
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/CreateDateCells.java62
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/EmbeddedObjects.java78
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/EventExample.java122
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/FrillsAndFills.java64
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/HSSFReadWrite.java251
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/HyperlinkFormula.java45
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/Hyperlinks.java97
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/InCellLists.java541
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/MergedCells.java49
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/NewLinesInCells.java57
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/NewSheet.java44
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/NewWorkbook.java38
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/OfficeDrawing.java330
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/OfficeDrawingWithGraphics.java113
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/Outlines.java181
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/ReadWriteWorkbook.java56
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/RepeatingRowsAndColumns.java64
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/SplitAndFreezePanes.java51
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/WorkingWithFonts.java63
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/ZoomSheet.java45
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hwmf/ROP2Table.java106
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hwmf/ROP3Table.java146
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/hwpf/Word2Forrest.java226
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/ss/AddDimensionedImage.java1011
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/ss/AligningCells.java81
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/ss/BusinessPlan.java346
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/ss/CalendarDemo.java259
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/ss/CellStyleDetails.java98
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/ss/ConditionalFormats.java732
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/ss/DrawingBorders.java107
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/ss/ExcelComparator.java690
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/ss/LinkedDropDownLists.java206
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/ss/LoadEmbedded.java134
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/ss/LoanCalculator.java319
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/ss/SSPerformanceTest.java256
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/ss/TimesheetDemo.java234
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/ss/ToCSV.java740
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/ss/formula/CalculateMortgage.java91
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/ss/formula/CheckFunctionsSupported.java162
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/ss/formula/SettingExternalFunction.java93
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/ss/formula/UserDefinedFunctionExample.java80
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/ss/formula/mortgage-calculation.xlsbin0 -> 37376 bytes
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/ss/html/HSSFHtmlHelper.java66
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/ss/html/HtmlHelper.java40
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/ss/html/ToHtml.java506
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/ss/html/XSSFHtmlHelper.java59
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/ss/html/excelStyle.css73
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/ss/html/package-info.java22
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/util/TempFileUtils.java47
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xslf/AddVideoToPptx.java.txt251
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xslf/BarChartDemo.java169
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xslf/ChartFromScratch.java187
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xslf/DataExtraction.java101
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xslf/DoughnutChartFromScratch.java167
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xslf/LinkVideoToPptx.java120
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xslf/MergePresentations.java51
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xslf/PieChartDemo.java123
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xslf/Tutorial1.java80
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xslf/Tutorial2.java88
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xslf/Tutorial3.java51
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xslf/Tutorial4.java96
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xslf/Tutorial5.java52
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xslf/Tutorial6.java63
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xslf/Tutorial7.java92
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xslf/bar-chart-data.txt12
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xslf/bar-chart-template.pptxbin0 -> 44410 bytes
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xslf/pie-chart-data.txt4
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xslf/pie-chart-template.pptxbin0 -> 55297 bytes
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xslf/tutorial/Step1.java71
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xslf/tutorial/Step2.java79
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/eventusermodel/FromHowTo.java163
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/eventusermodel/LoadPasswordProtectedXlsxStreaming.java60
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/eventusermodel/XLSX2CSV.java263
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/streaming/DeferredGeneration.java54
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/streaming/HybridStreaming.java78
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/streaming/Outlining.java54
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/streaming/SavePasswordProtectedXlsx.java104
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/AligningCells.java139
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/BarAndLineChart.java194
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/BarChart.java124
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/BigGridDemo.java304
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/CalendarDemo.java242
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/CellComments.java88
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/CreateCell.java88
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/CreatePivotTable.java106
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/CreatePivotTable2.java125
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/CreateTable.java87
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/CreateUserDefinedDataFormats.java67
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/CustomXMLMapping.java47
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/EmbeddedObjects.java67
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/ExcelChartWithTargetLine.java234
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/FillsAndColors.java65
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/FitSheetToOnePage.java46
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/HeadersAndFooters.java84
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/HyperlinkExample.java96
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/IterateCells.java54
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/LineChart.java128
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/LoadPasswordProtectedXlsx.java83
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/MergingCells.java51
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/NewLinesInCells.java58
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/Outlining.java78
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/ScatterChart.java121
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/SelectedSheet.java45
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/ShiftRows.java60
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/SplitAndFreezePanes.java52
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/WorkbookProperties.java62
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/WorkingWithBorders.java65
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/WorkingWithFonts.java107
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/WorkingWithPageSetup.java82
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/WorkingWithPictures.java79
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/WorkingWithRichText.java70
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/BarChartExample.java145
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/BetterHeaderFooterExample.java56
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/ChartFromScratch.java154
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/HeaderFooterTable.java105
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/SimpleDocument.java136
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/SimpleDocumentWithHeader.java70
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/SimpleImages.java93
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/SimpleTable.java199
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/UpdateEmbeddedDoc.java181
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/bar-chart-data.txt12
-rw-r--r--poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/bar-chart-template.docxbin0 -> 37656 bytes
-rw-r--r--poi-examples/src/main/java9/module-info.classbin0 -> 978 bytes
-rw-r--r--poi-examples/src/main/java9/module-info.java40
-rw-r--r--poi-examples/src/main/jsp/HSSFExample.jsp116
-rw-r--r--poi-examples/src/main/ruby/Makefile332
-rw-r--r--poi-examples/src/main/ruby/Poi4R.i614
-rw-r--r--poi-examples/src/main/ruby/cpp/RubyIO.cpp44
-rw-r--r--poi-examples/src/main/ruby/java/org/apache/poi/RubyOutputStream.java62
-rw-r--r--poi-examples/src/main/ruby/tests/tc_base_tests.rb100
-rw-r--r--poi-examples/src/main/ruby/tests/tc_gc.rb32
-rw-r--r--poi-examples/src/main/ruby/tests/ts_all.rb20
-rw-r--r--poi-examples/src/main/scala/XSSFMain.scala56
-rw-r--r--poi-examples/src/main/scala/build.sbt23
-rw-r--r--poi-examples/src/test/java/org/apache/poi/integration/TestXLSX2CSV.java113
164 files changed, 21383 insertions, 0 deletions
diff --git a/poi-examples/build.gradle b/poi-examples/build.gradle
new file mode 100644
index 0000000000..5b1deb141f
--- /dev/null
+++ b/poi-examples/build.gradle
@@ -0,0 +1,99 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+import java.util.regex.Pattern
+
+plugins {
+ id 'java'
+ id 'maven-publish'
+ id 'java-library'
+}
+
+final String JAVA9_SRC = 'src/main/java9'
+final String JAVA9_OUT = "${buildDir}/classes/java9/main/"
+final String VERSIONS9 = 'META-INF/versions/9'
+
+sourceSets {
+ main {
+ if (JavaVersion.current() != JavaVersion.VERSION_1_8) {
+ output.dir(JAVA9_OUT, builtBy: 'cacheJava9')
+ }
+ }
+}
+
+
+dependencies {
+ api project(':poi-ooxml')
+ api project(':poi-scratchpad')
+ implementation project(path: ':poi-ooxml', configuration: 'archives')
+ implementation project(path: ':poi-ooxml-full', configuration: 'archives')
+ implementation project(path: ':poi-scratchpad', configuration: 'archives')
+
+ implementation "org.apache.logging.log4j:log4j-core:${log4jVersion}"
+
+ testImplementation project(path: ':ooxml', configuration: 'tests')
+ testImplementation project(path: ':main', configuration: 'tests')
+}
+
+final String MODULE_NAME = 'org.apache.poi.examples'
+final Pattern MODULE_REGEX = ~'\\.jar$'
+final List MAIN_MODULE_PATH = sourceSets.main.runtimeClasspath.findAll{ it.path =~ MODULE_REGEX }.collect{ it.parent }.unique()
+
+java {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+ withSourcesJar()
+}
+
+task compileJava9(type: JavaCompile) {
+ dependsOn 'compileJava', ':poi-ooxml:jar', ':poi-scratchpad:jar'
+
+ sourceCompatibility = 9
+ targetCompatibility = 9
+ destinationDirectory = file(JAVA9_OUT + VERSIONS9)
+ source = file(JAVA9_SRC)
+ classpath = files()
+ options.compilerArgs = [
+ '--patch-module', "${MODULE_NAME}=${sourceSets.main.output.classesDirs.asPath}",
+ '--module-path', files(MAIN_MODULE_PATH).asPath
+ ]
+}
+
+task cacheJava9(type: Copy) {
+ dependsOn 'compileJava9'
+
+ from(file(JAVA9_OUT + VERSIONS9))
+ into(JAVA9_SRC)
+}
+
+jar {
+ destinationDirectory = file("../build/dist/maven/${project.archivesBaseName}")
+
+ if (JavaVersion.current() == JavaVersion.VERSION_1_8) {
+ into('META-INF/versions/9') {
+ from JAVA9_SRC include '*.class'
+ }
+ }
+
+ manifest {
+ attributes('Automatic-Module-Name': MODULE_NAME, 'Multi-Release': 'true')
+ }
+}
+
+sourcesJar {
+ destinationDirectory = file("../build/dist/maven/${project.archivesBaseName}")
+}
diff --git a/poi-examples/src/main/clojure/SpreadSheetDemo.clj b/poi-examples/src/main/clojure/SpreadSheetDemo.clj
new file mode 100644
index 0000000000..fbef7c991c
--- /dev/null
+++ b/poi-examples/src/main/clojure/SpreadSheetDemo.clj
@@ -0,0 +1,36 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+(ns poi.core
+ (:gen-class)
+ (:use [clojure.java.io :only [input-stream]])
+ (:import [org.apache.poi.ss.usermodel WorkbookFactory DataFormatter]))
+
+
+(defn sheets [wb] (map #(.getSheetAt wb %1) (range 0 (.getNumberOfSheets wb))))
+
+(defn print-all [wb]
+ (let [df (DataFormatter.)]
+ (doseq [sheet (sheets wb)]
+ (doseq [row (seq sheet)]
+ (doseq [cell (seq row)]
+ (println (.formatAsString (.getAddress cell)) ": " (.formatCellValue df cell)))))))
+
+(defn -main [& args]
+ (when-let [name (first args)]
+ (let [wb (WorkbookFactory/create (input-stream name))]
+ (print-all wb))))
diff --git a/poi-examples/src/main/groovy/SpreadSheetDemo.groovy b/poi-examples/src/main/groovy/SpreadSheetDemo.groovy
new file mode 100644
index 0000000000..b9f30c0ce6
--- /dev/null
+++ b/poi-examples/src/main/groovy/SpreadSheetDemo.groovy
@@ -0,0 +1,108 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+import org.apache.poi.ss.usermodel.*
+import org.apache.poi.ss.util.*
+import java.io.File
+
+if (args.length == 0) {
+ println "Use:"
+ println " SpreadSheetDemo <excel-file> [output-file]"
+ return 1
+}
+
+File f = new File(args[0])
+DataFormatter formatter = new DataFormatter()
+WorkbookFactory.create(f,null,true).withCloseable { workbook ->
+ println "Has ${workbook.getNumberOfSheets()} sheets"
+
+ // Dump the contents of the spreadsheet
+ (0..<workbook.getNumberOfSheets()).each { sheetNum ->
+ println "Sheet ${sheetNum} is called ${workbook.getSheetName(sheetNum)}"
+
+ def sheet = workbook.getSheetAt(sheetNum)
+ sheet.each { row ->
+ def nonEmptyCells = row.grep { c -> c.getCellType() != Cell.CELL_TYPE_BLANK }
+ println " Row ${row.getRowNum()} has ${nonEmptyCells.size()} non-empty cells:"
+ nonEmptyCells.each { c ->
+ def cRef = [c] as CellReference
+ println " * ${cRef.formatAsString()} = ${formatter.formatCellValue(c)}"
+ }
+ }
+ }
+
+ // Add two new sheets and populate
+ CellStyle headerStyle = makeHeaderStyle(workbook)
+ Sheet ns1 = workbook.createSheet("Generated 1")
+ exportHeader(ns1, headerStyle, null, ["ID","Title","Num"] as String[])
+ ns1.createRow(1).createCell(0).setCellValue("TODO - Populate with data")
+
+ Sheet ns2 = workbook.createSheet("Generated 2")
+ exportHeader(ns2, headerStyle, "This is a demo sheet",
+ ["ID","Title","Date","Author","Num"] as String[])
+ ns2.createRow(2).createCell(0).setCellValue(1)
+ ns2.createRow(3).createCell(0).setCellValue(4)
+ ns2.createRow(4).createCell(0).setCellValue(1)
+
+ // Save
+ File output = File.createTempFile("output-", (f.getName() =~ /(\.\w+$)/)[0][0])
+ output.withOutputStream { os -> workbook.write(os) }
+ println "Saved as ${output}"
+}
+
+CellStyle makeHeaderStyle(Workbook wb) {
+ int HEADER_HEIGHT = 18
+ CellStyle style = wb.createCellStyle()
+
+ style.setFillForegroundColor(IndexedColors.AQUA.getIndex())
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND)
+
+ Font font = wb.createFont()
+ font.setFontHeightInPoints((short)HEADER_HEIGHT)
+ font.setBold(true)
+ style.setFont(font)
+
+ return style
+}
+void exportHeader(Sheet s, CellStyle headerStyle, String info, String[] headers) {
+ Row r
+ int rn = 0
+ int HEADER_HEIGHT = 18
+ // Do they want an info row at the top?
+ if (info != null && !info.isEmpty()) {
+ r = s.createRow(rn)
+ r.setHeightInPoints(HEADER_HEIGHT+1)
+ rn++
+
+ Cell c = r.createCell(0)
+ c.setCellValue(info)
+ c.setCellStyle(headerStyle)
+ s.addMergedRegion(new CellRangeAddress(0,0,0,headers.length-1))
+ }
+ // Create the header row, of the right size
+ r = s.createRow(rn)
+ r.setHeightInPoints(HEADER_HEIGHT+1)
+ // Add the column headings
+ headers.eachWithIndex { col, idx ->
+ Cell c = r.createCell(idx)
+ c.setCellValue(col)
+ c.setCellStyle(headerStyle)
+ s.autoSizeColumn(idx)
+ }
+ // Make all the columns filterable
+ s.setAutoFilter(new CellRangeAddress(rn, rn, 0, headers.length-1))
+}
diff --git a/poi-examples/src/main/groovy/build.gradle b/poi-examples/src/main/groovy/build.gradle
new file mode 100644
index 0000000000..79bccbcdeb
--- /dev/null
+++ b/poi-examples/src/main/groovy/build.gradle
@@ -0,0 +1,43 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+// Add the POI core and OOXML support dependencies into your gradle build,
+// along with all of Groovy so it can run as a standalone script
+apply plugin: 'groovy'
+repositories {
+ mavenCentral()
+}
+dependencies {
+ compile 'org.codehaus.groovy:groovy-all:2.4.13'
+ compile 'org.apache.poi:poi:5.0.0'
+ compile 'org.apache.poi:poi-ooxml:5.0.0'
+}
+
+// Our files are in the current directory
+sourceSets {
+ main { groovy { srcDirs = ['.'] } }
+}
+
+// Run out read demo by default
+tasks.withType(JavaExec) {
+ classpath = sourceSets.main.runtimeClasspath
+}
+task runScript(type: JavaExec) {
+ main = "SpreadSheetDemo"
+ args = ["../../../test-data/spreadsheet/Simple.xls"]
+}
+defaultTasks 'runScript'
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/crypt/OOXMLPasswordsTry.java b/poi-examples/src/main/java/org/apache/poi/examples/crypt/OOXMLPasswordsTry.java
new file mode 100644
index 0000000000..406d6dc335
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/crypt/OOXMLPasswordsTry.java
@@ -0,0 +1,89 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.crypt;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.security.GeneralSecurityException;
+import java.util.Optional;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
+import org.apache.poi.poifs.crypt.Decryptor;
+import org.apache.poi.poifs.crypt.EncryptionInfo;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+
+/**
+ * Tries a list of possible passwords for an OOXML protected file
+ *
+ * Note that this isn't very fast, and is aimed at when you have
+ * just a few passwords to check.
+ * For serious processing, you'd be best off grabbing the hash
+ * out with POI or office2john.py, then running that against
+ * "John The Ripper" or GPU enabled version of "hashcat"
+ */
+public final class OOXMLPasswordsTry {
+
+ private OOXMLPasswordsTry() {}
+
+ @SuppressWarnings({"java:S106","java:S4823"})
+ public static void main(String[] args) throws Exception {
+ if (args.length < 2) {
+ System.err.println("Use:");
+ System.err.println(" OOXMLPasswordsTry <file.ooxml> <wordlist>");
+ System.exit(1);
+ }
+ String ooxml = args[0];
+ String words = args[1];
+
+ System.out.println("Trying passwords from " + words + " against " + ooxml);
+ System.out.println();
+
+ try (POIFSFileSystem fs = new POIFSFileSystem(new File(ooxml), true)) {
+ EncryptionInfo info = new EncryptionInfo(fs);
+ Decryptor d = Decryptor.getInstance(info);
+
+ final long start = System.currentTimeMillis();
+ final int[] count = { 0 };
+ Predicate<String> counter = s -> {
+ if (++count[0] % 1000 == 0) {
+ int secs = (int) ((System.currentTimeMillis() - start) / 1000);
+ System.out.println("Done " + count[0] + " passwords, " + secs + " seconds, last password " + s);
+ }
+ return true;
+ };
+
+ // Try each password in turn, reporting progress
+ try (Stream<String> lines = Files.lines(Paths.get(words))) {
+ Optional<String> found = lines.filter(counter).filter(w -> isValid(d, w)).findFirst();
+ System.out.println(found.map(s -> "Password found: " + s).orElse("Error - No password matched"));
+ }
+ }
+ }
+
+ private static boolean isValid(Decryptor dec, String password) {
+ try {
+ return dec.verifyPassword(password);
+ } catch (GeneralSecurityException e) {
+ return false;
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hpsf/CopyCompare.java b/poi-examples/src/main/java/org/apache/poi/examples/hpsf/CopyCompare.java
new file mode 100644
index 0000000000..c24afe1376
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hpsf/CopyCompare.java
@@ -0,0 +1,200 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hpsf;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+
+import org.apache.poi.hpsf.DocumentSummaryInformation;
+import org.apache.poi.hpsf.HPSFException;
+import org.apache.poi.hpsf.HPSFRuntimeException;
+import org.apache.poi.hpsf.PropertySet;
+import org.apache.poi.hpsf.PropertySetFactory;
+import org.apache.poi.hpsf.SummaryInformation;
+import org.apache.poi.hpsf.WritingNotSupportedException;
+import org.apache.poi.poifs.eventfilesystem.POIFSReader;
+import org.apache.poi.poifs.eventfilesystem.POIFSReaderEvent;
+import org.apache.poi.poifs.filesystem.DirectoryEntry;
+import org.apache.poi.poifs.filesystem.DocumentInputStream;
+import org.apache.poi.poifs.filesystem.EntryUtils;
+import org.apache.poi.poifs.filesystem.POIFSDocumentPath;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.util.TempFile;
+
+/**
+ * <p>This class copies a POI file system to a new file and compares the copy
+ * with the original.</p>
+ * <p>
+ * <p>Property set streams are copied logically, i.e. the application
+ * establishes a {@link org.apache.poi.hpsf.PropertySet} of an original property
+ * set, creates a {@link org.apache.poi.hpsf.PropertySet} and writes the
+ * {@link org.apache.poi.hpsf.PropertySet} to the destination POI file
+ * system. - Streams which are no property set streams are copied bit by
+ * bit.</p>
+ * <p>
+ * <p>The comparison of the POI file systems is done logically. That means that
+ * the two disk files containing the POI file systems do not need to be
+ * exactly identical. However, both POI file systems must contain the same
+ * files, and most of these files must be bitwise identical. Property set
+ * streams, however, are compared logically: they must have the same sections
+ * with the same attributes, and the sections must contain the same properties.
+ * Details like the ordering of the properties do not matter.</p>
+ */
+@SuppressWarnings({"java:S106","java:S4823"})
+public final class CopyCompare {
+ private CopyCompare() {}
+
+ private static final ThreadLocal<PrintStream> out = ThreadLocal.withInitial(() -> System.out);
+
+ /**
+ * Runs the example program. The application expects one or two arguments:
+ *
+ * <ol>
+ * <li>The first argument is the disk file name of the POI filesystem to copy.</li>
+ * <li>The second argument is optional. If it is given, it is the name of
+ * a disk file the copy of the POI filesystem will be written to. If it is
+ * not given, the copy will be written to a temporary file which will be
+ * deleted at the end of the program.</li>
+ * </ol>
+ *
+ * @param args Command-line arguments.
+ * @throws IOException if any I/O exception occurs.
+ * @throws UnsupportedEncodingException if a character encoding is not
+ * supported.
+ */
+ public static void main(final String[] args) throws IOException {
+ String originalFileName = null;
+ String copyFileName = null;
+
+ // Check the command-line arguments.
+ if (args.length == 1) {
+ originalFileName = args[0];
+ File f = TempFile.createTempFile("CopyOfPOIFileSystem-", ".ole2");
+ f.deleteOnExit();
+ copyFileName = f.getAbsolutePath();
+ } else if (args.length == 2) {
+ originalFileName = args[0];
+ copyFileName = args[1];
+ } else {
+ System.err.println("Usage: CopyCompare originPOIFS [copyPOIFS]");
+ System.exit(1);
+ }
+
+
+ // Read the origin POIFS using the eventing API.
+ final POIFSReader r = new POIFSReader();
+ try (final POIFSFileSystem poiFs = new POIFSFileSystem();
+ OutputStream fos = new FileOutputStream(copyFileName)) {
+ r.registerListener(e -> handleEvent(poiFs, e));
+ r.setNotifyEmptyDirectories(true);
+
+ r.read(new File(originalFileName));
+
+ // Write the new POIFS to disk.
+ poiFs.writeFilesystem(fos);
+ }
+
+ // Read all documents from the original POI file system and compare them with
+ // the equivalent document from the copy.
+ try (POIFSFileSystem opfs = new POIFSFileSystem(new File(originalFileName));
+ POIFSFileSystem cpfs = new POIFSFileSystem(new File(copyFileName))) {
+ final DirectoryEntry oRoot = opfs.getRoot();
+ final DirectoryEntry cRoot = cpfs.getRoot();
+ out.get().println(EntryUtils.areDirectoriesIdentical(oRoot, cRoot) ? "Equal" : "Not equal");
+ }
+ }
+
+ public static void setOut(PrintStream ps) {
+ out.set(ps);
+ }
+
+ private interface InputStreamSupplier {
+ InputStream get() throws IOException, WritingNotSupportedException;
+ }
+
+ /**
+ * The method is called by POI's eventing API for each file in the origin POIFS.
+ */
+ public static void handleEvent(final POIFSFileSystem poiFs, final POIFSReaderEvent event) {
+ // The following declarations are shortcuts for accessing the "event" object.
+ final DocumentInputStream stream = event.getStream();
+
+ try {
+
+ // Find out whether the current document is a property set stream or not.
+ InputStreamSupplier su;
+ if (stream != null && PropertySet.isPropertySetStream(stream)) {
+ // Yes, the current document is a property set stream. Let's create
+ // a PropertySet instance from it.
+ PropertySet ps = PropertySetFactory.create(stream);
+
+ // Copy the property set to the destination POI file system.
+ final PropertySet mps;
+ if (ps instanceof DocumentSummaryInformation) {
+ mps = new DocumentSummaryInformation(ps);
+ } else if (ps instanceof SummaryInformation) {
+ mps = new SummaryInformation(ps);
+ } else {
+ mps = new PropertySet(ps);
+ }
+ su = mps::toInputStream;
+ } else {
+ // No, the current document is not a property set stream.
+ // We copy it unmodified to the destination POIFS.
+ su = event::getStream;
+ }
+
+ try (InputStream is = su.get()) {
+ final POIFSDocumentPath path = event.getPath();
+
+ // Ensures that the directory hierarchy for a document in a POI fileystem is in place.
+ // Get the root directory. It does not have to be created since it always exists in a POIFS.
+ DirectoryEntry de = poiFs.getRoot();
+ if (File.separator.equals(path.toString())) {
+ de.setStorageClsid(event.getStorageClassId());
+ }
+
+ for (int i=0; i<path.length(); i++) {
+ String subDir = path.getComponent(i);
+ if (de.hasEntry(subDir)) {
+ de = (DirectoryEntry)de.getEntry(subDir);
+ } else {
+ de = de.createDirectory(subDir);
+ if (i == path.length()-1) {
+ de.setStorageClsid(event.getStorageClassId());
+ }
+ }
+ }
+
+ if (event.getName() != null) {
+ de.createDocument(event.getName(), is);
+ }
+ }
+
+ } catch (HPSFException | IOException ex) {
+ // According to the definition of the processPOIFSReaderEvent method we cannot pass checked
+ // exceptions to the caller.
+ throw new HPSFRuntimeException("Could not read file " + event.getPath() + "/" + event.getName(), ex);
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hpsf/ModifyDocumentSummaryInformation.java b/poi-examples/src/main/java/org/apache/poi/examples/hpsf/ModifyDocumentSummaryInformation.java
new file mode 100644
index 0000000000..b42b936768
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hpsf/ModifyDocumentSummaryInformation.java
@@ -0,0 +1,159 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hpsf;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.Date;
+
+import org.apache.poi.hpsf.CustomProperties;
+import org.apache.poi.hpsf.DocumentSummaryInformation;
+import org.apache.poi.hpsf.PropertySetFactory;
+import org.apache.poi.hpsf.SummaryInformation;
+import org.apache.poi.poifs.filesystem.DirectoryEntry;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+
+/**
+ * <p>This is a sample application showing how to easily modify properties in
+ * the summary information and in the document summary information. The
+ * application reads the name of a POI filesystem from the command line and
+ * performs the following actions:</p>
+ *
+ * <ul>
+ *
+ * <li><p>Open the POI filesystem.</p></li>
+ *
+ * <li><p>Read the summary information.</p></li>
+ *
+ * <li><p>Read and print the "author" property.</p></li>
+ *
+ * <li><p>Change the author to "Rainer Klute".</p></li>
+ *
+ * <li><p>Read the document summary information.</p></li>
+ *
+ * <li><p>Read and print the "category" property.</p></li>
+ *
+ * <li><p>Change the category to "POI example".</p></li>
+ *
+ * <li><p>Read the custom properties (if available).</p></li>
+ *
+ * <li><p>Insert a new custom property.</p></li>
+ *
+ * <li><p>Write the custom properties back to the document summary
+ * information.</p></li>
+ *
+ * <li><p>Write the summary information to the POI filesystem.</p></li>
+ *
+ * <li><p>Write the document summary information to the POI filesystem.</p></li>
+ *
+ * <li><p>Write the POI filesystem back to the original file.</p></li>
+ *
+ * </ul>
+ */
+@SuppressWarnings({"java:S106","java:S4823"})
+public final class ModifyDocumentSummaryInformation {
+
+ private ModifyDocumentSummaryInformation() {}
+
+ /**
+ * <p>Main method - see class description.</p>
+ *
+ * @param args The command-line parameters.
+ */
+ public static void main(final String[] args) throws Exception {
+ /* Read the name of the POI filesystem to modify from the command line.
+ * For brevity to boundary check is performed on the command-line
+ * arguments. */
+ File summaryFile = new File(args[0]);
+
+ /* Open the POI filesystem. */
+ try (POIFSFileSystem poifs = new POIFSFileSystem(summaryFile, false)) {
+
+ /* Read the summary information. */
+ DirectoryEntry dir = poifs.getRoot();
+ SummaryInformation si;
+ try {
+ si = (SummaryInformation) PropertySetFactory.create(
+ dir, SummaryInformation.DEFAULT_STREAM_NAME);
+ } catch (FileNotFoundException ex) {
+ // There is no summary information yet. We have to create a new one
+ si = PropertySetFactory.newSummaryInformation();
+ }
+ assert(si != null);
+
+ /* Change the author to "Rainer Klute". Any former author value will
+ * be lost. If there has been no author yet, it will be created. */
+ si.setAuthor("Rainer Klute");
+ System.out.println("Author changed to " + si.getAuthor() + ".");
+
+
+ /* Handling the document summary information is analogous to handling
+ * the summary information. An additional feature, however, are the
+ * custom properties. */
+
+ /* Read the document summary information. */
+ DocumentSummaryInformation dsi;
+ try {
+ dsi = (DocumentSummaryInformation) PropertySetFactory.create(
+ dir, DocumentSummaryInformation.DEFAULT_STREAM_NAME);
+ } catch (FileNotFoundException ex) {
+ /* There is no document summary information yet. We have to create a
+ * new one. */
+ dsi = PropertySetFactory.newDocumentSummaryInformation();
+ }
+ assert(dsi != null);
+
+ /* Change the category to "POI example". Any former category value will
+ * be lost. If there has been no category yet, it will be created. */
+ dsi.setCategory("POI example");
+ System.out.println("Category changed to " + dsi.getCategory() + ".");
+
+ /* Read the custom properties. If there are no custom properties yet,
+ * the application has to create a new CustomProperties object. It will
+ * serve as a container for custom properties. */
+ CustomProperties customProperties = dsi.getCustomProperties();
+ if (customProperties == null)
+ customProperties = new CustomProperties();
+
+ /* Insert some custom properties into the container. */
+ customProperties.put("Key 1", "Value 1");
+ customProperties.put("Schl\u00fcssel 2", "Wert 2");
+ customProperties.put("Sample Number", 12345);
+ customProperties.put("Sample Boolean", Boolean.TRUE);
+ customProperties.put("Sample Date", new Date());
+
+ /* Read a custom property. */
+ Object value = customProperties.get("Sample Number");
+ System.out.println("Custom Sample Number is now " + value);
+
+ /* Write the custom properties back to the document summary
+ * information. */
+ dsi.setCustomProperties(customProperties);
+
+ /* Write the summary information and the document summary information
+ * to the POI filesystem. */
+ si.write(dir, SummaryInformation.DEFAULT_STREAM_NAME);
+ dsi.write(dir, DocumentSummaryInformation.DEFAULT_STREAM_NAME);
+
+ /* Write the POI filesystem back to the original file. Please note that
+ * in production code you should take care when write directly to the
+ * origin, to make sure you don't loose things on error */
+ poifs.writeFilesystem();
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hpsf/ReadCustomPropertySets.java b/poi-examples/src/main/java/org/apache/poi/examples/hpsf/ReadCustomPropertySets.java
new file mode 100644
index 0000000000..ca8cba1ce9
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hpsf/ReadCustomPropertySets.java
@@ -0,0 +1,109 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hpsf;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.poi.hpsf.HPSFRuntimeException;
+import org.apache.poi.hpsf.NoPropertySetStreamException;
+import org.apache.poi.hpsf.Property;
+import org.apache.poi.hpsf.PropertySet;
+import org.apache.poi.hpsf.PropertySetFactory;
+import org.apache.poi.hpsf.Section;
+import org.apache.poi.poifs.eventfilesystem.POIFSReader;
+import org.apache.poi.poifs.eventfilesystem.POIFSReaderEvent;
+
+/**
+ * <p>Sample application showing how to read a document's custom property set.
+ * Call it with the document's file name as command-line parameter.</p>
+ *
+ * <p>Explanations can be found in the HPSF HOW-TO.</p>
+ */
+@SuppressWarnings({"java:S106","java:S4823"})
+public final class ReadCustomPropertySets {
+
+ private ReadCustomPropertySets() {}
+
+ /**
+ * <p>Runs the example program.</p>
+ *
+ * @param args Command-line arguments (unused).
+ * @throws IOException if any I/O exception occurs.
+ */
+ public static void main(final String[] args) throws IOException {
+ final String filename = args[0];
+ POIFSReader r = new POIFSReader();
+
+ /* Register a listener for *all* documents. */
+ r.registerListener(ReadCustomPropertySets::processPOIFSReaderEvent);
+ r.read(new File(filename));
+ }
+
+
+ public static void processPOIFSReaderEvent(final POIFSReaderEvent event) {
+ final String streamName = event.getPath() + event.getName();
+ PropertySet ps;
+ try {
+ ps = PropertySetFactory.create(event.getStream());
+ } catch (NoPropertySetStreamException ex) {
+ out("No property set stream: \"" + streamName + "\"");
+ return;
+ } catch (Exception ex) {
+ throw new HPSFRuntimeException("Property set stream \"" + streamName + "\": " + ex);
+ }
+
+ /* Print the name of the property set stream: */
+ out("Property set stream \"" + streamName + "\":");
+
+ /* Print the number of sections: */
+ final long sectionCount = ps.getSectionCount();
+ out(" No. of sections: " + sectionCount);
+
+ /* Print the list of sections: */
+ List<Section> sections = ps.getSections();
+ int nr = 0;
+ for (Section sec : sections) {
+ /* Print a single section: */
+ out(" Section " + nr++ + ":");
+ String s = sec.getFormatID().toString();
+ s = s.substring(0, s.length() - 1);
+ out(" Format ID: " + s);
+
+ /* Print the number of properties in this section. */
+ int propertyCount = sec.getPropertyCount();
+ out(" No. of properties: " + propertyCount);
+
+ /* Print the properties: */
+ Property[] properties = sec.getProperties();
+ for (Property p : properties) {
+ /* Print a single property: */
+ long id = p.getID();
+ long type = p.getType();
+ Object value = p.getValue();
+ out(" Property ID: " + id + ", type: " + type +
+ ", value: " + value);
+ }
+ }
+ }
+
+ private static void out(final String msg) {
+ System.out.println(msg);
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hpsf/ReadTitle.java b/poi-examples/src/main/java/org/apache/poi/examples/hpsf/ReadTitle.java
new file mode 100644
index 0000000000..b901a89a3d
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hpsf/ReadTitle.java
@@ -0,0 +1,64 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hpsf;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.poi.hpsf.PropertySetFactory;
+import org.apache.poi.hpsf.SummaryInformation;
+import org.apache.poi.poifs.eventfilesystem.POIFSReader;
+import org.apache.poi.poifs.eventfilesystem.POIFSReaderEvent;
+
+/**
+ * <p>Sample application showing how to read a OLE 2 document's
+ * title. Call it with the document's file name as command line
+ * parameter.</p>
+ *
+ * <p>Explanations can be found in the HPSF HOW-TO.</p>
+ */
+@SuppressWarnings({"java:S106","java:S4823"})
+public final class ReadTitle {
+ private ReadTitle() {}
+
+ /**
+ * <p>Runs the example program.</p>
+ *
+ * @param args Command-line arguments. The first command-line argument must
+ * be the name of a POI filesystem to read.
+ * @throws IOException if any I/O exception occurs.
+ */
+ public static void main(final String[] args) throws IOException {
+ final String filename = args[0];
+ POIFSReader r = new POIFSReader();
+ r.registerListener(ReadTitle::processPOIFSReaderEvent, SummaryInformation.DEFAULT_STREAM_NAME);
+ r.read(new File(filename));
+ }
+
+
+ private static void processPOIFSReaderEvent(final POIFSReaderEvent event) {
+ SummaryInformation si;
+ try {
+ si = (SummaryInformation) PropertySetFactory.create(event.getStream());
+ } catch (Exception ex) {
+ throw new RuntimeException("Property set stream \"" + event.getPath() + event.getName() + "\": " + ex);
+ }
+ final String title = si.getTitle();
+ System.out.println(title != null ? "Title: \"" + title + "\"" : "Document has no title.");
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hpsf/WriteAuthorAndTitle.java b/poi-examples/src/main/java/org/apache/poi/examples/hpsf/WriteAuthorAndTitle.java
new file mode 100644
index 0000000000..94ceaf6c03
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hpsf/WriteAuthorAndTitle.java
@@ -0,0 +1,174 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hpsf;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.poi.hpsf.HPSFRuntimeException;
+import org.apache.poi.hpsf.MarkUnsupportedException;
+import org.apache.poi.hpsf.NoPropertySetStreamException;
+import org.apache.poi.hpsf.PropertySet;
+import org.apache.poi.hpsf.PropertySetFactory;
+import org.apache.poi.hpsf.Section;
+import org.apache.poi.hpsf.SummaryInformation;
+import org.apache.poi.hpsf.Variant;
+import org.apache.poi.hpsf.WritingNotSupportedException;
+import org.apache.poi.hpsf.wellknown.PropertyIDMap;
+import org.apache.poi.poifs.eventfilesystem.POIFSReader;
+import org.apache.poi.poifs.eventfilesystem.POIFSReaderEvent;
+import org.apache.poi.poifs.filesystem.DirectoryEntry;
+import org.apache.poi.poifs.filesystem.DocumentInputStream;
+import org.apache.poi.poifs.filesystem.POIFSDocumentPath;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+
+/**
+ * <p>This class is a sample application which shows how to write or modify the
+ * author and title property of an OLE 2 document. This could be done in two
+ * different ways:</p>
+ *
+ * <ul>
+ *
+ * <li><p>The first approach is to open the OLE 2 file as a POI filesystem
+ * (see class {@link POIFSFileSystem}), read the summary information property
+ * set (see classes {@link SummaryInformation} and {@link PropertySet}), write
+ * the author and title properties into it and write the property set back into
+ * the POI filesystem.</p></li>
+ *
+ * <li><p>The second approach does not modify the original POI filesystem, but
+ * instead creates a new one. All documents from the original POIFS are copied
+ * to the destination POIFS, except for the summary information stream. The
+ * latter is modified by setting the author and title property before writing
+ * it to the destination POIFS. It there are several summary information streams
+ * in the original POIFS - e.g. in subordinate directories - they are modified
+ * just the same.</p></li>
+ *
+ * </ul>
+ *
+ * <p>This sample application takes the second approach. It expects the name of
+ * the existing POI filesystem's name as its first command-line parameter and
+ * the name of the output POIFS as the second command-line argument. The
+ * program then works as described above: It copies nearly all documents
+ * unmodified from the input POI filesystem to the output POI filesystem. If it
+ * encounters a summary information stream it reads its properties. Then it sets
+ * the "author" and "title" properties to new values and writes the modified
+ * summary information stream into the output file.</p>
+ *
+ * <p>Further explanations can be found in the HPSF HOW-TO.</p>
+ */
+@SuppressWarnings({"java:S106","java:S4823"})
+public final class WriteAuthorAndTitle {
+ private WriteAuthorAndTitle() {}
+
+ /**
+ * <p>Runs the example program.</p>
+ *
+ * @param args Command-line arguments. The first command-line argument must
+ * be the name of a POI filesystem to read.
+ * @throws IOException if any I/O exception occurs.
+ */
+ public static void main(final String[] args) throws IOException {
+ /* Check whether we have exactly two command-line arguments. */
+ if (args.length != 2) {
+ System.err.println("Usage: WriteAuthorAndTitle originPOIFS destinationPOIFS");
+ System.exit(1);
+ }
+
+ /* Read the names of the origin and destination POI filesystems. */
+ final String srcName = args[0];
+ final String dstName = args[1];
+
+ /* Read the origin POIFS using the eventing API. The real work is done
+ * in the class ModifySICopyTheRest which is registered here as a
+ * POIFSReader. */
+ try (POIFSFileSystem poifs = new POIFSFileSystem();
+ OutputStream out = new FileOutputStream(dstName)) {
+ final POIFSReader r = new POIFSReader();
+ r.registerListener(e -> handleEvent(poifs, e));
+ r.read(new File(srcName));
+
+ /* Write the new POIFS to disk. */
+ poifs.writeFilesystem(out);
+ }
+ }
+
+ private interface InputStreamSupplier {
+ InputStream get() throws IOException, WritingNotSupportedException;
+ }
+
+ /**
+ * The method is called by POI's eventing API for each file in the origin POIFS.
+ */
+ private static void handleEvent(final POIFSFileSystem poiFs, final POIFSReaderEvent event) {
+ // The following declarations are shortcuts for accessing the "event" object.
+ final DocumentInputStream stream = event.getStream();
+
+ try {
+ final InputStreamSupplier isSup;
+
+ // Find out whether the current document is a property set stream or not.
+ if (PropertySet.isPropertySetStream(stream)) {
+ // Yes, the current document is a property set stream. Let's create a PropertySet instance from it.
+ PropertySet ps = PropertySetFactory.create(stream);
+
+ // Now we know that we really have a property set.
+ // The next step is to find out whether it is a summary information or not.
+ if (ps.isSummaryInformation()) {
+ // Create a mutable property set as a copy of the original read-only property set.
+ ps = new PropertySet(ps);
+
+ // Retrieve the section containing the properties to modify.
+ // A summary information property set contains exactly one section.
+ final Section s = ps.getSections().get(0);
+
+ // Set the properties.
+ s.setProperty(PropertyIDMap.PID_AUTHOR, Variant.VT_LPSTR, "Rainer Klute");
+ s.setProperty(PropertyIDMap.PID_TITLE, Variant.VT_LPWSTR, "Test");
+ }
+
+ isSup = ps::toInputStream;
+ } else {
+ // No, the current document is not a property set stream. We copy it unmodified to the destination POIFS.
+ isSup = event::getStream;
+ }
+
+ try (InputStream is = isSup.get()) {
+ final POIFSDocumentPath path = event.getPath();
+
+ // Ensures that the directory hierarchy for a document in a POI fileystem is in place.
+ // Get the root directory. It does not have to be created since it always exists in a POIFS.
+ DirectoryEntry de = poiFs.getRoot();
+
+ for (int i=0; i<path.length(); i++) {
+ String subDir = path.getComponent(i);
+ de = (de.hasEntry(subDir)) ? (DirectoryEntry)de.getEntry(subDir) : de.createDirectory(subDir);
+ }
+
+ de.createDocument(event.getName(), is);
+ }
+
+ } catch (MarkUnsupportedException | WritingNotSupportedException | IOException | NoPropertySetStreamException ex) {
+ // According to the definition of the processPOIFSReaderEvent method we cannot pass checked
+ // exceptions to the caller.
+ throw new HPSFRuntimeException("Could not read file " + event.getPath() + "/" + event.getName(), ex);
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hpsf/WriteTitle.java b/poi-examples/src/main/java/org/apache/poi/examples/hpsf/WriteTitle.java
new file mode 100644
index 0000000000..a9a50cf8e4
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hpsf/WriteTitle.java
@@ -0,0 +1,104 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hpsf;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.poi.hpsf.Property;
+import org.apache.poi.hpsf.PropertySet;
+import org.apache.poi.hpsf.Section;
+import org.apache.poi.hpsf.SummaryInformation;
+import org.apache.poi.hpsf.Variant;
+import org.apache.poi.hpsf.WritingNotSupportedException;
+import org.apache.poi.hpsf.wellknown.PropertyIDMap;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+
+/**
+ * <p>This class is a simple sample application showing how to create a property
+ * set and write it to disk.</p>
+ */
+@SuppressWarnings({"java:S106","java:S4823"})
+public final class WriteTitle {
+
+ private WriteTitle() {}
+
+ /**
+ * <p>Runs the example program.</p>
+ *
+ * @param args Command-line arguments. The first and only command-line
+ * argument is the name of the POI file system to create.
+ * @throws IOException if any I/O exception occurs.
+ * @throws WritingNotSupportedException if HPSF does not (yet) support
+ * writing a certain property type.
+ */
+ public static void main(final String[] args)
+ throws WritingNotSupportedException, IOException
+ {
+ /* Check whether we have exactly one command-line argument. */
+ if (args.length != 1)
+ {
+ System.err.println("Usage: " + WriteTitle.class.getName() + "destinationPOIFS");
+ System.exit(1);
+ }
+
+ final String fileName = args[0];
+
+ /* Create a mutable property set. Initially it contains a single section
+ * with no properties. */
+ final PropertySet mps = new PropertySet();
+
+ /* Retrieve the section the property set already contains. */
+ final Section ms = mps.getSections().get(0);
+
+ /* Turn the property set into a summary information property. This is
+ * done by setting the format ID of its first section to
+ * SectionIDMap.SUMMARY_INFORMATION_ID. */
+ ms.setFormatID(SummaryInformation.FORMAT_ID);
+
+ /* Create an empty property. */
+ final Property p = new Property();
+
+ /* Fill the property with appropriate settings so that it specifies the
+ * document's title. */
+ p.setID(PropertyIDMap.PID_TITLE);
+ p.setType(Variant.VT_LPWSTR);
+ p.setValue("Sample title");
+
+ /* Place the property into the section. */
+ ms.setProperty(p);
+
+ /* Create the POI file system the property set is to be written to.
+ * For writing the property set into a POI file system it has to be
+ * handed over to the POIFS.createDocument() method as an input stream
+ * which produces the bytes making out the property set stream. */
+ try (final POIFSFileSystem poiFs = new POIFSFileSystem();
+ final InputStream is = mps.toInputStream();
+ final FileOutputStream fos = new FileOutputStream(fileName)) {
+
+ /* Create the summary information property set in the POI file
+ * system. It is given the default name most (if not all) summary
+ * information property sets have. */
+ poiFs.createDocument(is, SummaryInformation.DEFAULT_STREAM_NAME);
+
+ /* Write the whole POI file system to a disk file. */
+ poiFs.writeFilesystem(fos);
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hslf/ApacheconEU08.java b/poi-examples/src/main/java/org/apache/poi/examples/hslf/ApacheconEU08.java
new file mode 100644
index 0000000000..53d3c46077
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hslf/ApacheconEU08.java
@@ -0,0 +1,460 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hslf;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.geom.Rectangle2D;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+import org.apache.poi.sl.draw.DrawTableShape;
+import org.apache.poi.sl.draw.SLGraphics;
+import org.apache.poi.sl.usermodel.AutoShape;
+import org.apache.poi.sl.usermodel.GroupShape;
+import org.apache.poi.sl.usermodel.ShapeType;
+import org.apache.poi.sl.usermodel.Slide;
+import org.apache.poi.sl.usermodel.SlideShow;
+import org.apache.poi.sl.usermodel.TableCell;
+import org.apache.poi.sl.usermodel.TableShape;
+import org.apache.poi.sl.usermodel.TextBox;
+import org.apache.poi.sl.usermodel.TextParagraph;
+import org.apache.poi.sl.usermodel.TextRun;
+import org.apache.poi.sl.usermodel.TextShape.TextPlaceholder;
+import org.apache.poi.sl.usermodel.VerticalAlignment;
+
+/**
+ * Presentation for Fast Feather Track on ApacheconEU 2008
+ *
+ * @author Yegor Kozlov
+ */
+@SuppressWarnings("java:S1192")
+public final class ApacheconEU08 {
+
+ private ApacheconEU08() {}
+
+ public static void main(String[] args) throws IOException {
+ // use HSLFSlideShow or XMLSlideShow
+ try (SlideShow<?,?> ppt = new HSLFSlideShow()) {
+ ppt.setPageSize(new Dimension(720, 540));
+
+ slide1(ppt);
+ slide2(ppt);
+ slide3(ppt);
+ slide4(ppt);
+ slide5(ppt);
+ slide6(ppt);
+ slide7(ppt);
+ slide8(ppt);
+ slide9(ppt);
+ slide10(ppt);
+ slide11(ppt);
+ slide12(ppt);
+
+ String ext = ppt.getClass().getName().contains("HSLF") ? "ppt" : "pptx";
+ try (FileOutputStream out = new FileOutputStream("apachecon_eu_08." + ext)) {
+ ppt.write(out);
+ }
+ }
+ }
+
+ public static void slide1(SlideShow<?,?> ppt) throws IOException {
+ Slide<?,?> slide = ppt.createSlide();
+
+ TextBox<?,?> box1 = slide.createTextBox();
+ box1.setTextPlaceholder(TextPlaceholder.CENTER_TITLE);
+ box1.setText("POI-HSLF");
+ box1.setAnchor(new Rectangle(54, 78, 612, 115));
+
+ TextBox<?,?> box2 = slide.createTextBox();
+ box2.setTextPlaceholder(TextPlaceholder.CENTER_BODY);
+ box2.setText("Java API To Access Microsoft PowerPoint Format Files");
+ box2.setAnchor(new Rectangle(108, 204, 504, 138));
+
+ TextBox<?,?> box3 = slide.createTextBox();
+ box3.getTextParagraphs().get(0).getTextRuns().get(0).setFontSize(32d);
+ box3.setText(
+ "Yegor Kozlov\r" +
+ "yegor - apache - org");
+ box3.setHorizontalCentered(true);
+ box3.setAnchor(new Rectangle(206, 348, 310, 84));
+ }
+
+ public static void slide2(SlideShow<?,?> ppt) throws IOException {
+ Slide<?,?> slide = ppt.createSlide();
+
+ TextBox<?,?> box1 = slide.createTextBox();
+ box1.setTextPlaceholder(TextPlaceholder.TITLE);
+ box1.setText("What is HSLF?");
+ box1.setAnchor(new Rectangle(36, 21, 648, 90));
+
+ TextBox<?,?> box2 = slide.createTextBox();
+ box2.setTextPlaceholder(TextPlaceholder.BODY);
+ box2.setText("HorribleSLideshowFormat is the POI Project's pure Java implementation " +
+ "of the Powerpoint binary file format. \r" +
+ "POI sub-project since 2005\r" +
+ "Started by Nick Burch, Yegor Kozlov joined soon after");
+ box2.setAnchor(new Rectangle(36, 126, 648, 356));
+ }
+
+ public static void slide3(SlideShow<?,?> ppt) throws IOException {
+ Slide<?,?> slide = ppt.createSlide();
+
+ TextBox<?,?> box1 = slide.createTextBox();
+ box1.setTextPlaceholder(TextPlaceholder.TITLE);
+ box1.setText("HSLF in a Nutshell");
+ box1.setAnchor(new Rectangle(36, 15, 648, 65));
+
+ TextBox<?,?> box2 = slide.createTextBox();
+ box2.setTextPlaceholder(TextPlaceholder.BODY);
+ box2.setText(
+ "HSLF provides a way to read, create and modify MS PowerPoint presentations\r" +
+ "Pure Java API - you don't need PowerPoint to read and write *.ppt files\r" +
+ "Comprehensive support of PowerPoint objects\r" +
+ "Rich text\r" +
+ "Tables\r" +
+ "Shapes\r" +
+ "Pictures\r" +
+ "Master slides\r" +
+ "Access to low level data structures"
+ );
+
+ List<? extends TextParagraph<?,?,?>> tp = box2.getTextParagraphs();
+ for (int i : new byte[]{0,1,2,8}) {
+ tp.get(i).getTextRuns().get(0).setFontSize(28d);
+ }
+ for (int i : new byte[]{3,4,5,6,7}) {
+ tp.get(i).getTextRuns().get(0).setFontSize(24d);
+ tp.get(i).setIndentLevel(1);
+ }
+ box2.setAnchor(new Rectangle(36, 80, 648, 400));
+ }
+
+ public static void slide4(SlideShow<?,?> ppt) throws IOException {
+ Slide<?,?> slide = ppt.createSlide();
+
+ String[][] txt1 = {
+ {"Note"},
+ {"This presentation was created programmatically using POI HSLF"}
+ };
+ TableShape<?,?> table1 = slide.createTable(2, 1);
+ for (int i = 0; i < txt1.length; i++) {
+ for (int j = 0; j < txt1[i].length; j++) {
+ TableCell<?,?> cell = table1.getCell(i, j);
+ cell.setText(txt1[i][j]);
+ TextRun rt = cell.getTextParagraphs().get(0).getTextRuns().get(0);
+ rt.setFontSize(10d);
+ rt.setFontFamily("Arial");
+ rt.setBold(true);
+ if(i == 0){
+ rt.setFontSize(32d);
+ rt.setFontColor(Color.white);
+ cell.setFillColor(new Color(0, 153, 204));
+ } else {
+ rt.setFontSize(28d);
+ cell.setFillColor(new Color(235, 239, 241));
+ }
+ cell.setVerticalAlignment(VerticalAlignment.MIDDLE);
+ }
+ }
+
+ DrawTableShape dts = new DrawTableShape(table1);
+ dts.setAllBorders(1.0, Color.black);
+ dts.setOutsideBorders(4.0);
+
+ table1.setColumnWidth(0, 450);
+ table1.setRowHeight(0, 50);
+ table1.setRowHeight(1, 80);
+
+ Dimension dim = ppt.getPageSize();
+ Rectangle2D oldAnchor = table1.getAnchor();
+ table1.setAnchor(new Rectangle2D.Double((dim.width-450)/2d, 100, oldAnchor.getWidth(), oldAnchor.getHeight()));
+
+ TextBox<?,?> box1 = slide.createTextBox();
+ box1.setHorizontalCentered(true);
+ box1.getTextParagraphs().get(0).getTextRuns().get(0).setFontSize(24d);
+ box1.setText("The source code is available at\r" +
+ "http://people.apache.org/~yegor/apachecon_eu08/");
+ box1.setAnchor(new Rectangle(80, 356, 553, 65));
+ }
+
+ public static void slide5(SlideShow<?,?> ppt) throws IOException {
+ Slide<?,?> slide = ppt.createSlide();
+
+ TextBox<?,?> box1 = slide.createTextBox();
+ box1.setTextPlaceholder(TextPlaceholder.TITLE);
+ box1.setText("HSLF in Action - 1\rData Extraction");
+ box1.setAnchor(new Rectangle(36, 21, 648, 100));
+
+ TextBox<?,?> box2 = slide.createTextBox();
+ box2.setTextPlaceholder(TextPlaceholder.BODY);
+ box2.setText(
+ "Text from slides and notes\r" +
+ "Images\r" +
+ "Shapes and their properties (type, position in the slide, color, font, etc.)");
+ box2.setAnchor(new Rectangle(36, 150, 648, 300));
+ }
+
+ public static void slide6(SlideShow<?,?> ppt) throws IOException {
+ Slide<?,?> slide = ppt.createSlide();
+
+ TextBox<?,?> box1 = slide.createTextBox();
+ box1.setTextPlaceholder(TextPlaceholder.TITLE);
+ box1.setText("HSLF in Action - 2");
+ box1.setAnchor(new Rectangle(36, 20, 648, 90));
+
+ TextBox<?,?> box2 = slide.createTextBox();
+ box2.getTextParagraphs().get(0).getTextRuns().get(0).setFontSize(18d);
+ box2.setText("Creating a simple presentation from scratch");
+ box2.setAnchor(new Rectangle(170, 100, 364, 30));
+
+ TextBox<?,?> box3 = slide.createTextBox();
+ TextRun rt3 = box3.getTextParagraphs().get(0).getTextRuns().get(0);
+ rt3.setFontFamily("Courier New");
+ rt3.setFontSize(8d);
+ box3.setText(
+ "SlideShow ppt = new SlideShow();\u000b" +
+ "Slide slide = ppt.createSlide();\u000b" +
+ "\u000b" +
+ "TextBox box2 = new TextBox();\u000b" +
+ "box2.setHorizontalAlignment(TextBox.AlignCenter);\u000b" +
+ "box2.setVerticalAlignment(TextBox.AnchorMiddle);\u000b" +
+ "box2.getTextRun().setText(\"Java Code\");\u000b" +
+ "box2.getFill().setForegroundColor(new Color(187, 224, 227));\u000b" +
+ "box2.setLineColor(Color.black);\u000b" +
+ "box2.setLineWidth(0.75);\u000b" +
+ "box2.setAnchor(new Rectangle(66, 243, 170, 170));\u000b" +
+ "slide.addShape(box2);\u000b" +
+ "\u000b" +
+ "TextBox box3 = new TextBox();\u000b" +
+ "box3.setHorizontalAlignment(TextBox.AlignCenter);\u000b" +
+ "box3.setVerticalAlignment(TextBox.AnchorMiddle);\u000b" +
+ "box3.getTextRun().setText(\"*.ppt file\");\u000b" +
+ "box3.setLineWidth(0.75);\u000b" +
+ "box3.setLineColor(Color.black);\u000b" +
+ "box3.getFill().setForegroundColor(new Color(187, 224, 227));\u000b" +
+ "box3.setAnchor(new Rectangle(473, 243, 170, 170));\u000b" +
+ "slide.addShape(box3);\u000b" +
+ "\u000b" +
+ "AutoShape box4 = new AutoShape(ShapeTypes.Arrow);\u000b" +
+ "box4.getFill().setForegroundColor(new Color(187, 224, 227));\u000b" +
+ "box4.setLineWidth(0.75);\u000b" +
+ "box4.setLineColor(Color.black);\u000b" +
+ "box4.setAnchor(new Rectangle(253, 288, 198, 85));\u000b" +
+ "slide.addShape(box4);\u000b" +
+ "\u000b" +
+ "FileOutputStream out = new FileOutputStream(\"hslf-demo.ppt\");\u000b" +
+ "ppt.write(out);\u000b" +
+ "out.close();");
+ box3.setAnchor(new Rectangle(30, 150, 618, 411));
+ box3.setHorizontalCentered(true);
+ }
+
+ public static void slide7(SlideShow<?,?> ppt) throws IOException {
+ Slide<?,?> slide = ppt.createSlide();
+
+ TextBox<?,?> box2 = slide.createTextBox();
+ box2.setHorizontalCentered(true);
+ box2.setVerticalAlignment(VerticalAlignment.MIDDLE);
+ box2.setText("Java Code");
+ box2.setFillColor(new Color(187, 224, 227));
+ box2.setStrokeStyle(0.75, Color.black);
+ box2.setAnchor(new Rectangle(66, 243, 170, 170));
+
+ TextBox<?,?> box3 = slide.createTextBox();
+ box3.setHorizontalCentered(true);
+ box3.setVerticalAlignment(VerticalAlignment.MIDDLE);
+ box3.setText("*.ppt file");
+ box3.setFillColor(new Color(187, 224, 227));
+ box3.setStrokeStyle(0.75, Color.black);
+ box3.setAnchor(new Rectangle(473, 243, 170, 170));
+
+ AutoShape<?,?> box4 = slide.createAutoShape();
+ box4.setShapeType(ShapeType.RIGHT_ARROW);
+ box4.setFillColor(new Color(187, 224, 227));
+ box4.setStrokeStyle(0.75, Color.black);
+ box4.setAnchor(new Rectangle(253, 288, 198, 85));
+ }
+
+ public static void slide8(SlideShow<?,?> ppt) throws IOException {
+ Slide<?,?> slide = ppt.createSlide();
+
+ TextBox<?,?> box1 = slide.createTextBox();
+ box1.setTextPlaceholder(TextPlaceholder.TITLE);
+ box1.setText("Wait, there is more!");
+ box1.setAnchor(new Rectangle(36, 21, 648, 90));
+
+ TextBox<?,?> box2 = slide.createTextBox();
+ box2.setTextPlaceholder(TextPlaceholder.BODY);
+ box2.setText(
+ "Rich text\r" +
+ "Tables\r" +
+ "Pictures (JPEG, PNG, BMP, WMF, PICT)\r" +
+ "Comprehensive formatting features");
+ box2.setAnchor(new Rectangle(36, 126, 648, 356));
+ }
+
+ public static void slide9(SlideShow<?,?> ppt) throws IOException {
+ Slide<?,?> slide = ppt.createSlide();
+
+ TextBox<?,?> box1 = slide.createTextBox();
+ box1.setTextPlaceholder(TextPlaceholder.TITLE);
+ box1.setText("HSLF in Action - 3");
+ box1.setAnchor(new Rectangle(36, 20, 648, 50));
+
+ TextBox<?,?> box2 = slide.createTextBox();
+ box2.getTextParagraphs().get(0).getTextRuns().get(0).setFontSize(18d);
+ box2.setText("PPGraphics2D: PowerPoint Graphics2D driver");
+ box2.setAnchor(new Rectangle(178, 70, 387, 30));
+
+ TextBox<?,?> box3 = slide.createTextBox();
+ TextRun rt3 = box3.getTextParagraphs().get(0).getTextRuns().get(0);
+ rt3.setFontFamily("Courier New");
+ rt3.setFontSize(8d);
+ box3.setText(
+ "//bar chart data. The first value is the bar color, the second is the width\u000b" +
+ "Object[] def = new Object[]{\u000b" +
+ " Color.yellow, new Integer(100),\u000b" +
+ " Color.green, new Integer(150),\u000b" +
+ " Color.gray, new Integer(75),\u000b" +
+ " Color.red, new Integer(200),\u000b" +
+ "};\u000b" +
+ "\u000b" +
+ "SlideShow ppt = new SlideShow();\u000b" +
+ "Slide slide = ppt.createSlide();\u000b" +
+ "\u000b" +
+ "ShapeGroup group = new ShapeGroup();\u000b" +
+ "//define position of the drawing in the slide\u000b" +
+ "Rectangle bounds = new java.awt.Rectangle(200, 100, 350, 300);\u000b" +
+ "group.setAnchor(bounds);\u000b" +
+ "slide.addShape(group);\u000b" +
+ "Graphics2D graphics = new PPGraphics2D(group);\u000b" +
+ "\u000b" +
+ "//draw a simple bar graph\u000b" +
+ "int x = bounds.x + 50, y = bounds.y + 50;\u000b" +
+ "graphics.setFont(new Font(\"Arial\", Font.BOLD, 10));\u000b" +
+ "for (int i = 0, idx = 1; i < def.length; i+=2, idx++) {\u000b" +
+ " graphics.setColor(Color.black);\u000b" +
+ " int width = ((Integer)def[i+1]).intValue();\u000b" +
+ " graphics.drawString(\"Q\" + idx, x-20, y+20);\u000b" +
+ " graphics.drawString(width + \"%\", x + width + 10, y + 20);\u000b" +
+ " graphics.setColor((Color)def[i]);\u000b" +
+ " graphics.fill(new Rectangle(x, y, width, 30));\u000b" +
+ " y += 40;\u000b" +
+ "}\u000b" +
+ "graphics.setColor(Color.black);\u000b" +
+ "graphics.setFont(new Font(\"Arial\", Font.BOLD, 14));\u000b" +
+ "graphics.draw(bounds);\u000b" +
+ "graphics.drawString(\"Performance\", x + 70, y + 40);\u000b" +
+ "\u000b" +
+ "FileOutputStream out = new FileOutputStream(\"hslf-demo.ppt\");\u000b" +
+ "ppt.write(out);\u000b" +
+ "out.close();");
+ box3.setAnchor(new Rectangle(96, 110, 499, 378));
+ box3.setHorizontalCentered(true);
+ }
+
+ public static void slide10(SlideShow<?,?> ppt) throws IOException {
+ //bar chart data. The first value is the bar color, the second is the width
+ Object[] def = new Object[]{
+ Color.yellow, 100,
+ Color.green, 150,
+ Color.gray, 75,
+ Color.red, 200,
+ };
+
+ Slide<?,?> slide = ppt.createSlide();
+
+ GroupShape<?,?> group = slide.createGroup();
+ //define position of the drawing in the slide
+ Rectangle bounds = new java.awt.Rectangle(200, 100, 350, 300);
+ group.setAnchor(bounds);
+ Graphics2D graphics = new SLGraphics(group);
+
+ //draw a simple bar graph
+ int x = bounds.x + 50;
+ int y = bounds.y + 50;
+ graphics.setFont(new Font("Arial", Font.BOLD, 10));
+ for (int i = 0, idx = 1; i < def.length; i+=2, idx++) {
+ graphics.setColor(Color.black);
+ int width = (Integer) def[i + 1];
+ graphics.drawString("Q" + idx, x-20, y+20);
+ graphics.drawString(width + "%", x + width + 10, y + 20);
+ graphics.setColor((Color)def[i]);
+ graphics.fill(new Rectangle(x, y, width, 30));
+ y += 40;
+ }
+ graphics.setColor(Color.black);
+ graphics.setFont(new Font("Arial", Font.BOLD, 14));
+ graphics.draw(bounds);
+ graphics.drawString("Performance", x + 70, y + 40);
+
+ }
+
+ public static void slide11(SlideShow<?,?> ppt) throws IOException {
+ Slide<?,?> slide = ppt.createSlide();
+
+ TextBox<?,?> box1 = slide.createTextBox();
+ box1.setTextPlaceholder(TextPlaceholder.TITLE);
+ box1.setText("HSLF Development Plans");
+ box1.setAnchor(new Rectangle(36, 21, 648, 90));
+
+ TextBox<?,?> box2 = slide.createTextBox();
+ box2.setTextPlaceholder(TextPlaceholder.BODY);
+ box2.setText(
+ "Support for more PowerPoint functionality\r" +
+ "Rendering slides into java.awt.Graphics2D\r" +
+ "A way to export slides into images or other formats\r" +
+ "Integration with Apache FOP - Formatting Objects Processor\r" +
+ "Transformation of XSL-FO into PPT\r" +
+ "PPT2PDF transcoder"
+ );
+
+ List<? extends TextParagraph<?,?,?>> tp = box2.getTextParagraphs();
+ for (int i : new byte[]{0,1,3}) {
+ tp.get(i).getTextRuns().get(0).setFontSize(28d);
+ }
+ for (int i : new byte[]{2,4,5}) {
+ tp.get(i).getTextRuns().get(0).setFontSize(24d);
+ tp.get(i).setIndentLevel(1);
+ }
+
+ box2.setAnchor(new Rectangle(36, 126, 648, 400));
+ }
+
+ public static void slide12(SlideShow<?,?> ppt) throws IOException {
+ Slide<?,?> slide = ppt.createSlide();
+
+ TextBox<?,?> box1 = slide.createTextBox();
+ box1.setTextPlaceholder(TextPlaceholder.CENTER_TITLE);
+ box1.setText("Questions?");
+ box1.setAnchor(new Rectangle(54, 167, 612, 115));
+
+ TextBox<?,?> box2 = slide.createTextBox();
+ box2.setTextPlaceholder(TextPlaceholder.CENTER_BODY);
+ box2.setText(
+ "https://poi.apache.org/hslf/\r" +
+ "http://people.apache.org/~yegor");
+ box2.setAnchor(new Rectangle(108, 306, 504, 138));
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hslf/BulletsDemo.java b/poi-examples/src/main/java/org/apache/poi/examples/hslf/BulletsDemo.java
new file mode 100644
index 0000000000..5ab8b86a39
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hslf/BulletsDemo.java
@@ -0,0 +1,60 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hslf;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hslf.usermodel.HSLFSlide;
+import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+import org.apache.poi.hslf.usermodel.HSLFTextBox;
+import org.apache.poi.hslf.usermodel.HSLFTextParagraph;
+
+/**
+ * How to create a single-level bulleted list
+ * and change some of the bullet attributes
+ */
+public final class BulletsDemo {
+
+ public static void main(String[] args) throws IOException {
+ try (HSLFSlideShow ppt = new HSLFSlideShow()) {
+ HSLFSlide slide = ppt.createSlide();
+
+ HSLFTextBox shape = new HSLFTextBox();
+ HSLFTextParagraph rt = shape.getTextParagraphs().get(0);
+ rt.getTextRuns().get(0).setFontSize(42d);
+ rt.setBullet(true);
+ rt.setIndent(0d); //bullet offset
+ rt.setLeftMargin(50d); //text offset (should be greater than bullet offset)
+ rt.setBulletChar('\u263A'); //bullet character
+ shape.setText(
+ "January\r" +
+ "February\r" +
+ "March\r" +
+ "April");
+ slide.addShape(shape);
+
+ shape.setAnchor(new java.awt.Rectangle(50, 50, 500, 300)); //position of the text box in the slide
+ slide.addShape(shape);
+
+ try (FileOutputStream out = new FileOutputStream("bullets.ppt")) {
+ ppt.write(out);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hslf/CreateHyperlink.java b/poi-examples/src/main/java/org/apache/poi/examples/hslf/CreateHyperlink.java
new file mode 100644
index 0000000000..be8a227d1a
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hslf/CreateHyperlink.java
@@ -0,0 +1,64 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hslf;
+
+import java.awt.Rectangle;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hslf.usermodel.HSLFHyperlink;
+import org.apache.poi.hslf.usermodel.HSLFSlide;
+import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+import org.apache.poi.hslf.usermodel.HSLFTextBox;
+
+/**
+ * Demonstrates how to create hyperlinks in PowerPoint presentations
+ */
+public final class CreateHyperlink {
+
+ private CreateHyperlink() {}
+
+ public static void main(String[] args) throws IOException {
+ try (HSLFSlideShow ppt = new HSLFSlideShow()) {
+ HSLFSlide slideA = ppt.createSlide();
+ ppt.createSlide();
+ HSLFSlide slideC = ppt.createSlide();
+
+ // link to a URL
+ HSLFTextBox textBox1 = slideA.createTextBox();
+ textBox1.setText("Apache POI");
+ textBox1.setAnchor(new Rectangle(100, 100, 200, 50));
+
+ HSLFHyperlink link1 = textBox1.getTextParagraphs().get(0).getTextRuns().get(0).createHyperlink();
+ link1.linkToUrl("http://www.apache.org");
+ link1.setLabel(textBox1.getText());
+
+ // link to another slide
+ HSLFTextBox textBox2 = slideA.createTextBox();
+ textBox2.setText("Go to slide #3");
+ textBox2.setAnchor(new Rectangle(100, 300, 200, 50));
+
+ HSLFHyperlink link2 = textBox2.getTextParagraphs().get(0).getTextRuns().get(0).createHyperlink();
+ link2.linkToSlide(slideC);
+
+ try (FileOutputStream out = new FileOutputStream("hyperlink.ppt")) {
+ ppt.write(out);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hslf/DataExtraction.java b/poi-examples/src/main/java/org/apache/poi/examples/hslf/DataExtraction.java
new file mode 100644
index 0000000000..6996dc8751
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hslf/DataExtraction.java
@@ -0,0 +1,148 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hslf;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.poi.hslf.usermodel.HSLFObjectData;
+import org.apache.poi.hslf.usermodel.HSLFObjectShape;
+import org.apache.poi.hslf.usermodel.HSLFPictureData;
+import org.apache.poi.hslf.usermodel.HSLFPictureShape;
+import org.apache.poi.hslf.usermodel.HSLFShape;
+import org.apache.poi.hslf.usermodel.HSLFSlide;
+import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+import org.apache.poi.hslf.usermodel.HSLFSoundData;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hwpf.HWPFDocument;
+import org.apache.poi.hwpf.usermodel.Paragraph;
+import org.apache.poi.hwpf.usermodel.Range;
+import org.apache.poi.util.IOUtils;
+
+/**
+ * Demonstrates how you can extract misc embedded data from a ppt file
+ */
+@SuppressWarnings({"java:S106","java:S4823"})
+public final class DataExtraction {
+
+ private DataExtraction() {}
+
+ public static void main(String[] args) throws Exception {
+
+ if (args.length == 0) {
+ usage();
+ return;
+ }
+
+ try (FileInputStream fis = new FileInputStream(args[0]);
+ HSLFSlideShow ppt = new HSLFSlideShow(fis)) {
+
+ //extract all sound files embedded in this presentation
+ HSLFSoundData[] sound = ppt.getSoundData();
+ for (HSLFSoundData aSound : sound) {
+ handleSound(aSound);
+ }
+
+ int oleIdx = -1;
+ int picIdx = -1;
+ for (HSLFSlide slide : ppt.getSlides()) {
+ //extract embedded OLE documents
+ for (HSLFShape shape : slide.getShapes()) {
+ if (shape instanceof HSLFObjectShape) {
+ handleShape((HSLFObjectShape) shape, ++oleIdx);
+ } else if (shape instanceof HSLFPictureShape) {
+ handlePicture((HSLFPictureShape) shape, ++picIdx);
+ }
+ }
+ }
+ }
+ }
+
+ private static void handleShape(HSLFObjectShape ole, int oleIdx) throws IOException {
+ HSLFObjectData data = ole.getObjectData();
+ String name = ole.getInstanceName();
+ switch (name == null ? "" : name) {
+ case "Worksheet":
+ //read xls
+ handleWorkbook(data, name, oleIdx);
+ break;
+ case "Document":
+ //read the word document
+ handleDocument(data, name, oleIdx);
+ break;
+ default:
+ handleUnknown(data, ole.getProgId(), oleIdx);
+ break;
+ }
+
+ }
+
+ private static void handleWorkbook(HSLFObjectData data, String name, int oleIdx) throws IOException {
+ try (InputStream is = data.getInputStream();
+ HSSFWorkbook wb = new HSSFWorkbook(is);
+ FileOutputStream out = new FileOutputStream(name + "-(" + (oleIdx) + ").xls")) {
+ wb.write(out);
+ }
+ }
+
+ private static void handleDocument(HSLFObjectData data, String name, int oleIdx) throws IOException {
+ try (InputStream is = data.getInputStream();
+ HWPFDocument doc = new HWPFDocument(is);
+ FileOutputStream out = new FileOutputStream(name + "-(" + (oleIdx) + ").doc")) {
+ Range r = doc.getRange();
+ for (int k = 0; k < r.numParagraphs(); k++) {
+ Paragraph p = r.getParagraph(k);
+ System.out.println(p.text());
+ }
+
+ //save on disk
+ doc.write(out);
+ }
+ }
+
+ private static void handleUnknown(HSLFObjectData data, String name, int oleIdx) throws IOException {
+ try (InputStream is = data.getInputStream();
+ FileOutputStream out = new FileOutputStream(name + "-" + (oleIdx + 1) + ".dat")) {
+ IOUtils.copy(is, out);
+ }
+ }
+
+ private static void handlePicture(HSLFPictureShape p, int picIdx) throws IOException {
+ HSLFPictureData data = p.getPictureData();
+ String ext = data.getType().extension;
+ try (FileOutputStream out = new FileOutputStream("pict-" + picIdx + ext)) {
+ out.write(data.getData());
+ }
+ }
+
+ private static void handleSound(HSLFSoundData aSound) throws IOException {
+ String type = aSound.getSoundType(); //*.wav
+ String name = aSound.getSoundName(); //typically file name
+
+ //save the sound on disk
+ try (FileOutputStream out = new FileOutputStream(name + type)) {
+ out.write(aSound.getData());
+ }
+ }
+
+ private static void usage(){
+ System.out.println("Usage: DataExtraction ppt");
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hslf/Graphics2DDemo.java b/poi-examples/src/main/java/org/apache/poi/examples/hslf/Graphics2DDemo.java
new file mode 100644
index 0000000000..938b52e6d2
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hslf/Graphics2DDemo.java
@@ -0,0 +1,82 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hslf;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.io.FileOutputStream;
+
+import org.apache.poi.hslf.usermodel.HSLFGroupShape;
+import org.apache.poi.hslf.usermodel.HSLFSlide;
+import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+import org.apache.poi.sl.draw.SLGraphics;
+
+/**
+ * Demonstrates how to draw into a slide using the HSLF Graphics2D driver.
+ */
+public final class Graphics2DDemo {
+
+ private Graphics2DDemo() {}
+
+ /**
+ * A simple bar chart demo
+ */
+ public static void main(String[] args) throws Exception {
+ try (HSLFSlideShow ppt = new HSLFSlideShow();
+ FileOutputStream out = new FileOutputStream("hslf-graphics.ppt")) {
+ //bar chart data. The first value is the bar color, the second is the width
+ Object[] def = {
+ Color.yellow, 40,
+ Color.green, 60,
+ Color.gray, 30,
+ Color.red, 80,
+ };
+
+ HSLFSlide slide = ppt.createSlide();
+
+ HSLFGroupShape group = new HSLFGroupShape();
+ //define position of the drawing in the slide
+ Rectangle bounds = new Rectangle(200, 100, 350, 300);
+ group.setAnchor(bounds);
+ group.setInteriorAnchor(new Rectangle(0, 0, 100, 100));
+ slide.addShape(group);
+ Graphics2D graphics = new SLGraphics(group);
+
+ //draw a simple bar graph
+ int x = 10, y = 10;
+ graphics.setFont(new Font("Arial", Font.BOLD, 10));
+ for (int i = 0, idx = 1; i < def.length; i += 2, idx++) {
+ graphics.setColor(Color.black);
+ int width = (Integer) def[i + 1];
+ graphics.drawString("Q" + idx, x - 5, y + 10);
+ graphics.drawString(width + "%", x + width + 3, y + 10);
+ graphics.setColor((Color) def[i]);
+ graphics.fill(new Rectangle(x, y, width, 10));
+ y += 15;
+ }
+ graphics.setColor(Color.black);
+ graphics.setFont(new Font("Arial", Font.BOLD, 14));
+ graphics.draw(group.getInteriorAnchor());
+ graphics.drawString("Performance", x + 30, y + 10);
+
+ ppt.write(out);
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hslf/HeadersFootersDemo.java b/poi-examples/src/main/java/org/apache/poi/examples/hslf/HeadersFootersDemo.java
new file mode 100644
index 0000000000..4dd4349df5
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hslf/HeadersFootersDemo.java
@@ -0,0 +1,50 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.hslf;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hslf.model.HeadersFooters;
+import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+
+/**
+ * Demonstrates how to set headers / footers
+ */
+public final class HeadersFootersDemo {
+ private HeadersFootersDemo() {}
+
+ public static void main(String[] args) throws IOException {
+ try (HSLFSlideShow ppt = new HSLFSlideShow()) {
+ HeadersFooters slideHeaders = ppt.getSlideHeadersFooters();
+ slideHeaders.setFootersText("Created by POI-HSLF");
+ slideHeaders.setSlideNumberVisible(true);
+ slideHeaders.setDateTimeText("custom date time");
+
+ HeadersFooters notesHeaders = ppt.getNotesHeadersFooters();
+ notesHeaders.setFootersText("My notes footers");
+ notesHeaders.setHeaderText("My notes header");
+
+ ppt.createSlide();
+
+ try (FileOutputStream out = new FileOutputStream("headers_footers.ppt")) {
+ ppt.write(out);
+ }
+ }
+ }
+
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hslf/Hyperlinks.java b/poi-examples/src/main/java/org/apache/poi/examples/hslf/Hyperlinks.java
new file mode 100644
index 0000000000..307178d0e0
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hslf/Hyperlinks.java
@@ -0,0 +1,77 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hslf;
+
+import java.io.FileInputStream;
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.poi.hslf.usermodel.HSLFHyperlink;
+import org.apache.poi.hslf.usermodel.HSLFSimpleShape;
+import org.apache.poi.hslf.usermodel.HSLFSlide;
+import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+import org.apache.poi.hslf.usermodel.HSLFTextParagraph;
+import org.apache.poi.hslf.usermodel.HSLFTextRun;
+
+/**
+ * Demonstrates how to read hyperlinks from a presentation
+ */
+@SuppressWarnings({"java:S106", "java:S4823"})
+public final class Hyperlinks {
+
+ private Hyperlinks() {}
+
+ public static void main(String[] args) throws Exception {
+ for (String arg : args) {
+ try (FileInputStream is = new FileInputStream(arg);
+ HSLFSlideShow ppt = new HSLFSlideShow(is)) {
+
+ for (HSLFSlide slide : ppt.getSlides()) {
+ System.out.println("\nslide " + slide.getSlideNumber());
+
+ // read hyperlinks from the slide's text runs
+ System.out.println("- reading hyperlinks from the text runs");
+ slide.getTextParagraphs().stream().
+ flatMap(List::stream).
+ map(HSLFTextParagraph::getTextRuns).
+ flatMap(List::stream).
+ forEach(run -> out(run.getHyperlink(), run));
+
+ // in PowerPoint you can assign a hyperlink to a shape without text,
+ // for example to a Line object. The code below demonstrates how to
+ // read such hyperlinks
+ System.out.println("- reading hyperlinks from the slide's shapes");
+ slide.getShapes().stream().
+ filter(sh -> sh instanceof HSLFSimpleShape).
+ forEach(sh -> out(((HSLFSimpleShape) sh).getHyperlink(), null));
+ }
+ }
+ }
+ }
+
+ private static void out(HSLFHyperlink link, HSLFTextRun run) {
+ if (link == null) {
+ return;
+ }
+ String rawText = run == null ? null : run.getRawText();
+ //in ppt end index is inclusive
+ String formatStr = "title: %1$s, address: %2$s" + (rawText == null ? "" : ", start: %3$s, end: %4$s, substring: %5$s");
+ String line = String.format(Locale.ROOT, formatStr, link.getLabel(), link.getAddress(), link.getStartIndex(), link.getEndIndex(), rawText);
+ System.out.println(line);
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hslf/SoundFinder.java b/poi-examples/src/main/java/org/apache/poi/examples/hslf/SoundFinder.java
new file mode 100644
index 0000000000..0f6929fee7
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hslf/SoundFinder.java
@@ -0,0 +1,69 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.hslf;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+import org.apache.poi.hslf.record.InteractiveInfoAtom;
+import org.apache.poi.hslf.record.RecordTypes;
+import org.apache.poi.hslf.usermodel.HSLFShape;
+import org.apache.poi.hslf.usermodel.HSLFSlide;
+import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+import org.apache.poi.hslf.usermodel.HSLFSoundData;
+
+/**
+ * For each slide iterate over shapes and found associated sound data.
+ */
+@SuppressWarnings({"java:S106", "java:S4823"})
+public final class SoundFinder {
+ private SoundFinder() {}
+
+ public static void main(String[] args) throws IOException {
+ try (FileInputStream fis = new FileInputStream(args[0])) {
+ try (HSLFSlideShow ppt = new HSLFSlideShow(fis)) {
+ HSLFSoundData[] sounds = ppt.getSoundData();
+
+ for (HSLFSlide slide : ppt.getSlides()) {
+ for (HSLFShape shape : slide.getShapes()) {
+ int soundRef = getSoundReference(shape);
+ if (soundRef == -1) continue;
+
+
+ System.out.println("Slide[" + slide.getSlideNumber() + "], shape[" + shape.getShapeId() + "], soundRef: " + soundRef);
+ System.out.println(" " + sounds[soundRef].getSoundName());
+ System.out.println(" " + sounds[soundRef].getSoundType());
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Check if a given shape is associated with a sound.
+ * @return 0-based reference to a sound in the sound collection
+ * or -1 if the shape is not associated with a sound
+ */
+ private static int getSoundReference(HSLFShape shape){
+ int soundRef = -1;
+ //dive into the shape container and search for InteractiveInfoAtom
+ InteractiveInfoAtom info = shape.getClientDataRecord(RecordTypes.InteractiveInfo.typeID);
+ if (info != null && info.getAction() == InteractiveInfoAtom.ACTION_MEDIA) {
+ soundRef = info.getSoundRef();
+ }
+ return soundRef;
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hslf/TableDemo.java b/poi-examples/src/main/java/org/apache/poi/examples/hslf/TableDemo.java
new file mode 100644
index 0000000000..561ec717ab
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hslf/TableDemo.java
@@ -0,0 +1,132 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hslf;
+
+import java.awt.Color;
+import java.io.FileOutputStream;
+
+import org.apache.poi.hslf.usermodel.HSLFSlide;
+import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+import org.apache.poi.hslf.usermodel.HSLFTable;
+import org.apache.poi.hslf.usermodel.HSLFTableCell;
+import org.apache.poi.hslf.usermodel.HSLFTextRun;
+import org.apache.poi.sl.draw.DrawTableShape;
+import org.apache.poi.sl.usermodel.TextParagraph.TextAlign;
+import org.apache.poi.sl.usermodel.VerticalAlignment;
+
+/**
+ * Demonstrates how to create tables
+ */
+public final class TableDemo {
+
+ //test data for the first table
+ static final String[][] txt1 = {
+ {"INPUT FILE", "NUMBER OF RECORDS"},
+ {"Item File", "11,559"},
+ {"Vendor File", "502"},
+ {"Purchase History File - # of PO\u2019s\r(12/01/04 - 05/31/06)", "12,852"},
+ {"Purchase History File - # of PO Lines\r(12/01/04 - 05/31/06)", "53,523" },
+ {"Total PO History Spend", "$10,172,038"}
+ };
+
+ //test data for the second taable
+ static final String[][] txt2 = {
+ {"Data Source"},
+ {"CAS Internal Metrics - Item Master Summary\r" +
+ "CAS Internal Metrics - Vendor Summary\r" +
+ "CAS Internal Metrics - PO History Summary"}
+ };
+
+
+ public static void main(String[] args) throws Exception {
+ try (HSLFSlideShow ppt = new HSLFSlideShow()) {
+ HSLFSlide slide = ppt.createSlide();
+ create1stTable(slide);
+ create2ndTable(slide);
+
+ try (FileOutputStream out = new FileOutputStream("hslf-table.ppt")) {
+ ppt.write(out);
+ }
+ }
+ }
+
+ static void create1stTable(HSLFSlide slide) {
+ //six rows, two columns
+ HSLFTable table1 = slide.createTable(6, 2);
+ for (int i = 0; i < txt1.length; i++) {
+ for (int j = 0; j < txt1[i].length; j++) {
+ HSLFTableCell cell = table1.getCell(i, j);
+ HSLFTextRun rt = cell.getTextParagraphs().get(0).getTextRuns().get(0);
+ rt.setFontFamily("Arial");
+ rt.setFontSize(10d);
+ if(i == 0){
+ cell.getFill().setForegroundColor(new Color(227, 227, 227));
+ } else {
+ rt.setBold(true);
+ }
+ cell.setVerticalAlignment(VerticalAlignment.MIDDLE);
+ cell.setHorizontalCentered(true);
+ cell.setText(txt1[i][j]);
+ }
+ }
+
+ DrawTableShape dts1 = new DrawTableShape(table1);
+ dts1.setAllBorders(1.0, Color.black);
+
+ table1.setColumnWidth(0, 300);
+ table1.setColumnWidth(1, 150);
+
+ int pgWidth = slide.getSlideShow().getPageSize().width;
+ table1.moveTo((pgWidth - table1.getAnchor().getWidth())/2., 100.);
+ }
+
+ static void create2ndTable(HSLFSlide slide) {
+ //two rows, one column
+ HSLFTable table2 = slide.createTable(2, 1);
+ for (int i = 0; i < txt2.length; i++) {
+ for (int j = 0; j < txt2[i].length; j++) {
+ HSLFTableCell cell = table2.getCell(i, j);
+ HSLFTextRun rt = cell.getTextParagraphs().get(0).getTextRuns().get(0);
+ rt.setFontSize(10d);
+ rt.setFontFamily("Arial");
+ if(i == 0){
+ cell.getFill().setForegroundColor(new Color(0, 51, 102));
+ rt.setFontColor(Color.white);
+ rt.setBold(true);
+ rt.setFontSize(14d);
+ cell.setHorizontalCentered(true);
+ } else {
+ rt.getTextParagraph().setBullet(true);
+ rt.setFontSize(12d);
+ rt.getTextParagraph().setTextAlign(TextAlign.LEFT);
+ cell.setHorizontalCentered(false);
+ }
+ cell.setVerticalAlignment(VerticalAlignment.MIDDLE);
+ cell.setText(txt2[i][j]);
+ }
+ }
+ table2.setColumnWidth(0, 300);
+ table2.setRowHeight(0, 30);
+ table2.setRowHeight(1, 70);
+
+ DrawTableShape dts2 = new DrawTableShape(table2);
+ dts2.setOutsideBorders(Color.black, 1.0);
+
+ table2.moveTo(200, 400);
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hsmf/Msg2txt.java b/poi-examples/src/main/java/org/apache/poi/examples/hsmf/Msg2txt.java
new file mode 100644
index 0000000000..4ab88cf27a
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hsmf/Msg2txt.java
@@ -0,0 +1,158 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hsmf;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+
+import org.apache.poi.hsmf.MAPIMessage;
+import org.apache.poi.hsmf.datatypes.AttachmentChunks;
+import org.apache.poi.hsmf.exceptions.ChunkNotFoundException;
+
+/**
+ * Reads one or several Outlook MSG files and for each of them creates
+ * a text file from available chunks and a directory that contains
+ * attachments.
+ */
+@SuppressWarnings({"java:S106","java:S4823"})
+public class Msg2txt {
+
+ /**
+ * The stem used to create file names for the text file and the directory
+ * that contains the attachments.
+ */
+ private String fileNameStem;
+
+ /**
+ * The Outlook MSG file being processed.
+ */
+ private MAPIMessage msg;
+
+ public Msg2txt(String fileName) throws IOException {
+ fileNameStem = fileName;
+ if(fileNameStem.endsWith(".msg") || fileNameStem.endsWith(".MSG")) {
+ fileNameStem = fileNameStem.substring(0, fileNameStem.length() - 4);
+ }
+ msg = new MAPIMessage(fileName);
+ }
+
+ /**
+ * Processes the message.
+ *
+ * @throws IOException if an exception occurs while writing the message out
+ */
+ public void processMessage() throws IOException {
+ String txtFileName = fileNameStem + ".txt";
+ String attDirName = fileNameStem + "-att";
+ try (PrintWriter txtOut = new PrintWriter(txtFileName, "UTF-8")) {
+ try {
+ String displayFrom = msg.getDisplayFrom();
+ txtOut.println("From: " + displayFrom);
+ } catch (ChunkNotFoundException e) {
+ // ignore
+ }
+ try {
+ String displayTo = msg.getDisplayTo();
+ txtOut.println("To: " + displayTo);
+ } catch (ChunkNotFoundException e) {
+ // ignore
+ }
+ try {
+ String displayCC = msg.getDisplayCC();
+ txtOut.println("CC: " + displayCC);
+ } catch (ChunkNotFoundException e) {
+ // ignore
+ }
+ try {
+ String displayBCC = msg.getDisplayBCC();
+ txtOut.println("BCC: " + displayBCC);
+ } catch (ChunkNotFoundException e) {
+ // ignore
+ }
+ try {
+ String subject = msg.getSubject();
+ txtOut.println("Subject: " + subject);
+ } catch (ChunkNotFoundException e) {
+ // ignore
+ }
+ try {
+ String body = msg.getTextBody();
+ txtOut.println(body);
+ } catch (ChunkNotFoundException e) {
+ System.err.println("No message body");
+ }
+
+ AttachmentChunks[] attachments = msg.getAttachmentFiles();
+ if (attachments.length > 0) {
+ File d = new File(attDirName);
+ if (d.mkdir()) {
+ for (AttachmentChunks attachment : attachments) {
+ processAttachment(attachment, d);
+ }
+ } else {
+ System.err.println("Can't create directory " + attDirName);
+ }
+ }
+ }
+ }
+
+ /**
+ * Processes a single attachment: reads it from the Outlook MSG file and
+ * writes it to disk as an individual file.
+ *
+ * @param attachment the chunk group describing the attachment
+ * @param dir the directory in which to write the attachment file
+ * @throws IOException when any of the file operations fails
+ */
+ public void processAttachment(AttachmentChunks attachment,
+ File dir) throws IOException {
+ String fileName = attachment.getAttachFileName().toString();
+ if(attachment.getAttachLongFileName() != null) {
+ fileName = attachment.getAttachLongFileName().toString();
+ }
+
+ File f = new File(dir, fileName);
+ try (OutputStream fileOut = new FileOutputStream(f)) {
+ fileOut.write(attachment.getAttachData().getValue());
+ }
+ }
+
+ /**
+ * Processes the list of arguments as a list of names of Outlook MSG files.
+ *
+ * @param args the list of MSG files to process
+ */
+ public static void main(String[] args) {
+ if(args.length <= 0) {
+ System.err.println("No files names provided");
+ } else {
+ for (String arg : args) {
+ try {
+ Msg2txt processor = new Msg2txt(arg);
+ processor.processMessage();
+ } catch (IOException e) {
+ System.err.println("Could not process " + arg + ": " + e);
+ }
+ }
+ }
+ }
+
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hssf/eventusermodel/XLS2CSVmra.java b/poi-examples/src/main/java/org/apache/poi/examples/hssf/eventusermodel/XLS2CSVmra.java
new file mode 100644
index 0000000000..a0b393cf5b
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hssf/eventusermodel/XLS2CSVmra.java
@@ -0,0 +1,330 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hssf.eventusermodel;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder.SheetRecordCollectingListener;
+import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener;
+import org.apache.poi.hssf.eventusermodel.HSSFEventFactory;
+import org.apache.poi.hssf.eventusermodel.HSSFListener;
+import org.apache.poi.hssf.eventusermodel.HSSFRequest;
+import org.apache.poi.hssf.eventusermodel.MissingRecordAwareHSSFListener;
+import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord;
+import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord;
+import org.apache.poi.hssf.model.HSSFFormulaParser;
+import org.apache.poi.hssf.record.BOFRecord;
+import org.apache.poi.hssf.record.BlankRecord;
+import org.apache.poi.hssf.record.BoolErrRecord;
+import org.apache.poi.hssf.record.BoundSheetRecord;
+import org.apache.poi.hssf.record.FormulaRecord;
+import org.apache.poi.hssf.record.LabelRecord;
+import org.apache.poi.hssf.record.LabelSSTRecord;
+import org.apache.poi.hssf.record.NoteRecord;
+import org.apache.poi.hssf.record.NumberRecord;
+import org.apache.poi.hssf.record.RKRecord;
+import org.apache.poi.hssf.record.SSTRecord;
+import org.apache.poi.hssf.record.StringRecord;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+
+/**
+ * A XLS -&gt; CSV processor, that uses the MissingRecordAware
+ * EventModel code to ensure it outputs all columns and rows.
+ * @author Nick Burch
+ */
+@SuppressWarnings({"java:S106","java:S4823"})
+public class XLS2CSVmra implements HSSFListener {
+ private final int minColumns;
+ private final POIFSFileSystem fs;
+ private final PrintStream output;
+
+ private int lastRowNumber;
+ private int lastColumnNumber;
+
+ /** Should we output the formula, or the value it has? */
+ private final boolean outputFormulaValues = true;
+
+ /** For parsing Formulas */
+ private SheetRecordCollectingListener workbookBuildingListener;
+ private HSSFWorkbook stubWorkbook;
+
+ // Records we pick up as we process
+ private SSTRecord sstRecord;
+ private FormatTrackingHSSFListener formatListener;
+
+ /** So we known which sheet we're on */
+ private int sheetIndex = -1;
+ private BoundSheetRecord[] orderedBSRs;
+ private final List<BoundSheetRecord> boundSheetRecords = new ArrayList<>();
+
+ // For handling formulas with string results
+ private int nextRow;
+ private int nextColumn;
+ private boolean outputNextStringRecord;
+
+ /**
+ * Creates a new XLS -&gt; CSV converter
+ * @param fs The POIFSFileSystem to process
+ * @param output The PrintStream to output the CSV to
+ * @param minColumns The minimum number of columns to output, or -1 for no minimum
+ */
+ public XLS2CSVmra(POIFSFileSystem fs, PrintStream output, int minColumns) {
+ this.fs = fs;
+ this.output = output;
+ this.minColumns = minColumns;
+ }
+
+ /**
+ * Creates a new XLS -&gt; CSV converter
+ * @param filename The file to process
+ * @param minColumns The minimum number of columns to output, or -1 for no minimum
+ *
+ * @throws IOException if the file cannot be read or parsing the file fails
+ */
+ public XLS2CSVmra(String filename, int minColumns) throws IOException {
+ this(
+ new POIFSFileSystem(new FileInputStream(filename)),
+ System.out, minColumns
+ );
+ }
+
+ /**
+ * Initiates the processing of the XLS file to CSV
+ *
+ * @throws IOException if the workbook contained errors
+ */
+ public void process() throws IOException {
+ MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this);
+ formatListener = new FormatTrackingHSSFListener(listener);
+
+ HSSFEventFactory factory = new HSSFEventFactory();
+ HSSFRequest request = new HSSFRequest();
+
+ if(outputFormulaValues) {
+ request.addListenerForAllRecords(formatListener);
+ } else {
+ workbookBuildingListener = new SheetRecordCollectingListener(formatListener);
+ request.addListenerForAllRecords(workbookBuildingListener);
+ }
+
+ factory.processWorkbookEvents(request, fs);
+ }
+
+ /**
+ * Main HSSFListener method, processes events, and outputs the
+ * CSV as the file is processed.
+ */
+ @Override
+ public void processRecord(org.apache.poi.hssf.record.Record record) {
+ int thisRow = -1;
+ int thisColumn = -1;
+ String thisStr = null;
+
+ switch (record.getSid())
+ {
+ case BoundSheetRecord.sid:
+ boundSheetRecords.add((BoundSheetRecord)record);
+ break;
+ case BOFRecord.sid:
+ BOFRecord br = (BOFRecord)record;
+ if(br.getType() == BOFRecord.TYPE_WORKSHEET) {
+ // Create sub workbook if required
+ if(workbookBuildingListener != null && stubWorkbook == null) {
+ stubWorkbook = workbookBuildingListener.getStubHSSFWorkbook();
+ }
+
+ // Output the worksheet name
+ // Works by ordering the BSRs by the location of
+ // their BOFRecords, and then knowing that we
+ // process BOFRecords in byte offset order
+ sheetIndex++;
+ if(orderedBSRs == null) {
+ orderedBSRs = BoundSheetRecord.orderByBofPosition(boundSheetRecords);
+ }
+ output.println();
+ output.println(
+ orderedBSRs[sheetIndex].getSheetname() +
+ " [" + (sheetIndex+1) + "]:"
+ );
+ }
+ break;
+
+ case SSTRecord.sid:
+ sstRecord = (SSTRecord) record;
+ break;
+
+ case BlankRecord.sid:
+ BlankRecord brec = (BlankRecord) record;
+
+ thisRow = brec.getRow();
+ thisColumn = brec.getColumn();
+ thisStr = "";
+ break;
+ case BoolErrRecord.sid:
+ BoolErrRecord berec = (BoolErrRecord) record;
+
+ thisRow = berec.getRow();
+ thisColumn = berec.getColumn();
+ thisStr = "";
+ break;
+
+ case FormulaRecord.sid:
+ FormulaRecord frec = (FormulaRecord) record;
+
+ thisRow = frec.getRow();
+ thisColumn = frec.getColumn();
+
+ if(outputFormulaValues) {
+ if(Double.isNaN( frec.getValue() )) {
+ // Formula result is a string
+ // This is stored in the next record
+ outputNextStringRecord = true;
+ nextRow = frec.getRow();
+ nextColumn = frec.getColumn();
+ } else {
+ thisStr = formatListener.formatNumberDateCell(frec);
+ }
+ } else {
+ thisStr = '"' +
+ HSSFFormulaParser.toFormulaString(stubWorkbook, frec.getParsedExpression()) + '"';
+ }
+ break;
+ case StringRecord.sid:
+ if(outputNextStringRecord) {
+ // String for formula
+ StringRecord srec = (StringRecord)record;
+ thisStr = srec.getString();
+ thisRow = nextRow;
+ thisColumn = nextColumn;
+ outputNextStringRecord = false;
+ }
+ break;
+
+ case LabelRecord.sid:
+ LabelRecord lrec = (LabelRecord) record;
+
+ thisRow = lrec.getRow();
+ thisColumn = lrec.getColumn();
+ thisStr = '"' + lrec.getValue() + '"';
+ break;
+ case LabelSSTRecord.sid:
+ LabelSSTRecord lsrec = (LabelSSTRecord) record;
+
+ thisRow = lsrec.getRow();
+ thisColumn = lsrec.getColumn();
+ if(sstRecord == null) {
+ thisStr = '"' + "(No SST Record, can't identify string)" + '"';
+ } else {
+ thisStr = '"' + sstRecord.getString(lsrec.getSSTIndex()).toString() + '"';
+ }
+ break;
+ case NoteRecord.sid:
+ NoteRecord nrec = (NoteRecord) record;
+
+ thisRow = nrec.getRow();
+ thisColumn = nrec.getColumn();
+ // TODO: Find object to match nrec.getShapeId()
+ thisStr = '"' + "(TODO)" + '"';
+ break;
+ case NumberRecord.sid:
+ NumberRecord numrec = (NumberRecord) record;
+
+ thisRow = numrec.getRow();
+ thisColumn = numrec.getColumn();
+
+ // Format
+ thisStr = formatListener.formatNumberDateCell(numrec);
+ break;
+ case RKRecord.sid:
+ RKRecord rkrec = (RKRecord) record;
+
+ thisRow = rkrec.getRow();
+ thisColumn = rkrec.getColumn();
+ thisStr = '"' + "(TODO)" + '"';
+ break;
+ default:
+ break;
+ }
+
+ // Handle new row
+ if(thisRow != -1 && thisRow != lastRowNumber) {
+ lastColumnNumber = -1;
+ }
+
+ // Handle missing column
+ if(record instanceof MissingCellDummyRecord) {
+ MissingCellDummyRecord mc = (MissingCellDummyRecord)record;
+ thisRow = mc.getRow();
+ thisColumn = mc.getColumn();
+ thisStr = "";
+ }
+
+ // If we got something to print out, do so
+ if(thisStr != null) {
+ if(thisColumn > 0) {
+ output.print(',');
+ }
+ output.print(thisStr);
+ }
+
+ // Update column and row count
+ if(thisRow > -1)
+ lastRowNumber = thisRow;
+ if(thisColumn > -1)
+ lastColumnNumber = thisColumn;
+
+ // Handle end of row
+ if(record instanceof LastCellOfRowDummyRecord) {
+ // Print out any missing commas if needed
+ if(minColumns > 0) {
+ // Columns are 0 based
+ if(lastColumnNumber == -1) { lastColumnNumber = 0; }
+ for(int i=lastColumnNumber; i<(minColumns); i++) {
+ output.print(',');
+ }
+ }
+
+ // We're onto a new row
+ lastColumnNumber = -1;
+
+ // End the row
+ output.println();
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ if(args.length < 1) {
+ System.err.println("Use:");
+ System.err.println(" XLS2CSVmra <xls file> [min columns]");
+ System.exit(1);
+ }
+
+ int minColumns = -1;
+ if(args.length >= 2) {
+ minColumns = Integer.parseInt(args[1]);
+ }
+
+ XLS2CSVmra xls2csv = new XLS2CSVmra(args[0], minColumns);
+ xls2csv.process();
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/AddDimensionedImage.java b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/AddDimensionedImage.java
new file mode 100644
index 0000000000..129f9327da
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/AddDimensionedImage.java
@@ -0,0 +1,23 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+
+package org.apache.poi.examples.hssf.usermodel;
+
+/* Placeholder - this is now handled in the Common SS example **/
+public class AddDimensionedImage extends org.apache.poi.examples.ss.AddDimensionedImage {
+} \ No newline at end of file
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/Alignment.java b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/Alignment.java
new file mode 100644
index 0000000000..25affcb0f8
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/Alignment.java
@@ -0,0 +1,72 @@
+
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+
+package org.apache.poi.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFCellStyle;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+
+/**
+ * Shows how various alignment options work.
+ *
+ * @author Glen Stampoultzis (glens at apache.org)
+ */
+public class Alignment {
+ public static void main(String[] args) throws IOException {
+ try (HSSFWorkbook wb = new HSSFWorkbook()) {
+ HSSFSheet sheet = wb.createSheet("new sheet");
+ HSSFRow row = sheet.createRow(2);
+ createCell(wb, row, 0, HorizontalAlignment.CENTER);
+ createCell(wb, row, 1, HorizontalAlignment.CENTER_SELECTION);
+ createCell(wb, row, 2, HorizontalAlignment.FILL);
+ createCell(wb, row, 3, HorizontalAlignment.GENERAL);
+ createCell(wb, row, 4, HorizontalAlignment.JUSTIFY);
+ createCell(wb, row, 5, HorizontalAlignment.LEFT);
+ createCell(wb, row, 6, HorizontalAlignment.RIGHT);
+
+ // Write the output to a file
+ try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+
+ /**
+ * Creates a cell and aligns it a certain way.
+ *
+ * @param wb the workbook
+ * @param row the row to create the cell in
+ * @param column the column number to create the cell in
+ * @param align the alignment for the cell.
+ */
+ private static void createCell(HSSFWorkbook wb, HSSFRow row, int column, HorizontalAlignment align) {
+ HSSFCell cell = row.createCell(column);
+ cell.setCellValue("Align It");
+ HSSFCellStyle cellStyle = wb.createCellStyle();
+ cellStyle.setAlignment(align);
+ cell.setCellStyle(cellStyle);
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/BigExample.java b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/BigExample.java
new file mode 100644
index 0000000000..f50391ade8
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/BigExample.java
@@ -0,0 +1,169 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFCellStyle;
+import org.apache.poi.hssf.usermodel.HSSFDataFormat;
+import org.apache.poi.hssf.usermodel.HSSFFont;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined;
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.FillPatternType;
+
+/**
+ * Demonstrates many features of the user API at once. Used in the HOW-TO guide.
+ */
+public class BigExample {
+ public static void main(String[] args) throws IOException {
+ int rownum;
+
+ // create a new workbook
+ try (HSSFWorkbook wb = new HSSFWorkbook()) {
+ // create a new sheet
+ HSSFSheet s = wb.createSheet();
+ // declare a row object reference
+ HSSFRow r;
+ // declare a cell object reference
+ HSSFCell c;
+ // create 3 cell styles
+ HSSFCellStyle cs = wb.createCellStyle();
+ HSSFCellStyle cs2 = wb.createCellStyle();
+ HSSFCellStyle cs3 = wb.createCellStyle();
+ // create 2 fonts objects
+ HSSFFont f = wb.createFont();
+ HSSFFont f2 = wb.createFont();
+
+ //set font 1 to 12 point type
+ f.setFontHeightInPoints((short) 12);
+ //make it red
+ f.setColor(HSSFColorPredefined.RED.getIndex());
+ // make it bold
+ //arial is the default font
+ f.setBold(true);
+
+ //set font 2 to 10 point type
+ f2.setFontHeightInPoints((short) 10);
+ //make it the color at palette index 0xf (white)
+ f2.setColor(HSSFColorPredefined.WHITE.getIndex());
+ //make it bold
+ f2.setBold(true);
+
+ //set cell style
+ cs.setFont(f);
+ //set the cell format see HSSFDataFormat for a full list
+ cs.setDataFormat(HSSFDataFormat.getBuiltinFormat("($#,##0_);[Red]($#,##0)"));
+
+ //set a thin border
+ cs2.setBorderBottom(BorderStyle.THIN);
+ //fill w fg fill color
+ cs2.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+ // set foreground fill to red
+ cs2.setFillForegroundColor(HSSFColorPredefined.RED.getIndex());
+
+ // set the font
+ cs2.setFont(f2);
+
+ // set the sheet name to HSSF Test
+ wb.setSheetName(0, "HSSF Test");
+ // create a sheet with 300 rows (0-299)
+ for (rownum = 0; rownum < 300; rownum++) {
+ // create a row
+ r = s.createRow(rownum);
+ // on every other row
+ if ((rownum % 2) == 0) {
+ // make the row height bigger (in twips - 1/20 of a point)
+ r.setHeight((short) 0x249);
+ }
+
+ // create 50 cells (0-49) (the += 2 becomes apparent later
+ for (int cellnum = 0; cellnum < 50; cellnum += 2) {
+ // create a numeric cell
+ c = r.createCell(cellnum);
+ // do some goofy math to demonstrate decimals
+ c.setCellValue((rownum * 10000.0) + cellnum
+ + (rownum / 1000.0)
+ + (cellnum / 10000.0));
+
+ // on every other row
+ if ((rownum % 2) == 0) {
+ // set this cell to the first cell style we defined
+ c.setCellStyle(cs);
+ }
+
+ // create a string cell (see why += 2 in the
+ c = r.createCell(cellnum + 1);
+
+ // set the cell's string value to "TEST"
+ c.setCellValue("TEST");
+ // make this column a bit wider
+ s.setColumnWidth(cellnum + 1, (int) ((50 * 8) / ((double) 1 / 20)));
+
+ // on every other row
+ if ((rownum % 2) == 0) {
+ // set this to the white on red cell style
+ // we defined above
+ c.setCellStyle(cs2);
+ }
+
+ }
+ }
+
+ //draw a thick black border on the row at the bottom using BLANKS
+ // advance 2 rows
+ rownum++;
+ rownum++;
+
+ r = s.createRow(rownum);
+
+ // define the third style to be the default
+ // except with a thick black border at the bottom
+ cs3.setBorderBottom(BorderStyle.THICK);
+
+ //create 50 cells
+ for (int cellnum = 0; cellnum < 50; cellnum++) {
+ //create a blank type cell (no value)
+ c = r.createCell(cellnum);
+ // set it to the thick black border style
+ c.setCellStyle(cs3);
+ }
+
+ //end draw thick black border
+
+
+ // demonstrate adding/naming and deleting a sheet
+ // create a sheet, set its title then delete it
+ wb.createSheet();
+ wb.setSheetName(1, "DeletedSheet");
+ wb.removeSheetAt(1);
+ //end deleted sheet
+
+ // create a new file
+ try (FileOutputStream out = new FileOutputStream("workbook.xls")) {
+ // write the workbook to the output stream
+ // close our file (don't blow out our file handles
+ wb.write(out);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/Borders.java b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/Borders.java
new file mode 100644
index 0000000000..fba3b33214
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/Borders.java
@@ -0,0 +1,64 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFCellStyle;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined;
+import org.apache.poi.ss.usermodel.BorderStyle;
+
+/**
+ * Demonstrates how to create borders around cells.
+ */
+public class Borders {
+ public static void main(String[] args) throws IOException {
+ try (HSSFWorkbook wb = new HSSFWorkbook()) {
+ HSSFSheet sheet = wb.createSheet("new sheet");
+
+ // Create a row and put some cells in it. Rows are 0 based.
+ HSSFRow row = sheet.createRow(1);
+
+ // Create a cell and put a value in it.
+ HSSFCell cell = row.createCell(1);
+ cell.setCellValue(4);
+
+ // Style the cell with borders all around.
+ HSSFCellStyle style = wb.createCellStyle();
+ style.setBorderBottom(BorderStyle.THIN);
+ style.setBottomBorderColor(HSSFColorPredefined.BLACK.getIndex());
+ style.setBorderLeft(BorderStyle.THIN);
+ style.setLeftBorderColor(HSSFColorPredefined.GREEN.getIndex());
+ style.setBorderRight(BorderStyle.THIN);
+ style.setRightBorderColor(HSSFColorPredefined.BLUE.getIndex());
+ style.setBorderTop(BorderStyle.MEDIUM_DASHED);
+ style.setTopBorderColor(HSSFColorPredefined.ORANGE.getIndex());
+ cell.setCellStyle(style);
+
+ // Write the output to a file
+ try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/CellComments.java b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/CellComments.java
new file mode 100644
index 0000000000..6b6434b3e1
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/CellComments.java
@@ -0,0 +1,124 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFComment;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.ClientAnchor;
+import org.apache.poi.ss.usermodel.Comment;
+import org.apache.poi.ss.usermodel.CreationHelper;
+import org.apache.poi.ss.usermodel.Drawing;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.usermodel.RichTextString;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.usermodel.WorkbookFactory;
+
+/**
+ * Demonstrates how to work with excel cell comments.<p>
+ *
+ * Excel comment is a kind of a text shape,
+ * so inserting a comment is very similar to placing a text box in a worksheet
+ */
+public class CellComments {
+
+ public static void main(String[] args) throws IOException {
+ createWorkbook(false, ".xls");
+ createWorkbook(true, ".xlsx");
+ }
+
+ private static void createWorkbook(boolean xssf, String extension) throws IOException {
+ try (Workbook wb = WorkbookFactory.create(xssf)) {
+ Sheet sheet = wb.createSheet("Cell comments in POI " + extension);
+ CreationHelper creationHelper = wb.getCreationHelper();
+
+ // Create the drawing patriarch. This is the top level container for all shapes including cell comments.
+ Drawing<?> patr = sheet.createDrawingPatriarch();
+
+ //create a cell in row 3
+ Cell cell1 = sheet.createRow(3).createCell(1);
+ cell1.setCellValue(creationHelper.createRichTextString("Hello, World"));
+
+ //anchor defines size and position of the comment in worksheet
+ ClientAnchor clientAnchor = creationHelper.createClientAnchor();
+ clientAnchor.setCol1(4);
+ clientAnchor.setRow1(2);
+ clientAnchor.setCol2(6);
+ clientAnchor.setRow2(5);
+ Comment comment1 = patr.createCellComment(clientAnchor);
+
+ // set text in the comment
+ comment1.setString(creationHelper.createRichTextString("We can set comments in POI"));
+
+ //set comment author.
+ //you can see it in the status bar when moving mouse over the commented cell
+ comment1.setAuthor("Apache Software Foundation");
+
+ // The first way to assign comment to a cell is via Cell.setCellComment method
+ cell1.setCellComment(comment1);
+
+ //create another cell in row 6
+ Cell cell2 = sheet.createRow(6).createCell(1);
+ cell2.setCellValue(36.6);
+
+
+ clientAnchor = creationHelper.createClientAnchor();
+ clientAnchor.setCol1(4);
+ clientAnchor.setRow1(8);
+ clientAnchor.setCol2(6);
+ clientAnchor.setRow2(11);
+ Comment comment2 = patr.createCellComment(clientAnchor);
+ //modify background color of the comment, only available in HSSF currently
+ if (wb instanceof HSSFWorkbook) {
+ ((HSSFComment) comment2).setFillColor(204, 236, 255);
+ }
+
+ RichTextString string = creationHelper.createRichTextString("Normal body temperature");
+
+ //apply custom font to the text in the comment
+ Font font = wb.createFont();
+ font.setFontName("Arial");
+ font.setFontHeightInPoints((short) 10);
+ font.setBold(true);
+ font.setColor(IndexedColors.RED.getIndex());
+ string.applyFont(font);
+
+ comment2.setString(string);
+ comment2.setVisible(true); //by default comments are hidden. This one is always visible.
+
+ comment2.setAuthor("Bill Gates");
+
+ /*
+ * The second way to assign comment to a cell is to implicitly specify its row and column.
+ * Note, it is possible to set row and column of a non-existing cell.
+ * It works, the comment is visible.
+ */
+ comment2.setRow(6);
+ comment2.setColumn(1);
+
+ try (FileOutputStream out = new FileOutputStream("poi_comment" + extension)) {
+ wb.write(out);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/CellTypes.java b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/CellTypes.java
new file mode 100644
index 0000000000..5ba1656ff1
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/CellTypes.java
@@ -0,0 +1,46 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Date;
+
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.FormulaError;
+
+public class CellTypes {
+ public static void main(String[] args) throws IOException {
+ try (HSSFWorkbook wb = new HSSFWorkbook()) {
+ HSSFSheet sheet = wb.createSheet("new sheet");
+ HSSFRow row = sheet.createRow(2);
+ row.createCell(0).setCellValue(1.1);
+ row.createCell(1).setCellValue(new Date());
+ row.createCell(2).setCellValue("a string");
+ row.createCell(3).setCellValue(true);
+ row.createCell(4).setCellErrorValue(FormulaError.NUM);
+
+ // Write the output to a file
+ try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/CreateCells.java b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/CreateCells.java
new file mode 100644
index 0000000000..8994d6f17e
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/CreateCells.java
@@ -0,0 +1,55 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+
+/**
+ * Illustrates how to create cell values.
+ *
+ * @author Glen Stampoultzis (glens at apache.org)
+ */
+public class CreateCells {
+ public static void main(String[] args) throws IOException {
+ try (HSSFWorkbook wb = new HSSFWorkbook()) {
+ HSSFSheet sheet = wb.createSheet("new sheet");
+
+ // Create a row and put some cells in it. Rows are 0 based.
+ HSSFRow row = sheet.createRow(0);
+ // Create a cell and put a value in it.
+ HSSFCell cell = row.createCell(0);
+ cell.setCellValue(1);
+
+ // Or do it on one line.
+ row.createCell(1).setCellValue(1.2);
+ row.createCell(2).setCellValue("This is a string");
+ row.createCell(3).setCellValue(true);
+
+ // Write the output to a file
+ try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/CreateDateCells.java b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/CreateDateCells.java
new file mode 100644
index 0000000000..b77e0d1474
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/CreateDateCells.java
@@ -0,0 +1,62 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Date;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFCellStyle;
+import org.apache.poi.hssf.usermodel.HSSFDataFormat;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+
+/**
+ * An example on how to cells with dates. The important thing to note
+ * about dates is that they are really normal numeric cells that are
+ * formatted specially.
+ */
+public class CreateDateCells {
+ public static void main(String[] args) throws IOException {
+ try (HSSFWorkbook wb = new HSSFWorkbook()) {
+ HSSFSheet sheet = wb.createSheet("new sheet");
+
+ // Create a row and put some cells in it. Rows are 0 based.
+ HSSFRow row = sheet.createRow(0);
+
+ // Create a cell and put a date value in it. The first cell is not styled as a date.
+ HSSFCell cell = row.createCell(0);
+ cell.setCellValue(new Date());
+
+ // we style the second cell as a date (and time). It is important to create a new cell style from the workbook
+ // otherwise you can end up modifying the built in style and effecting not only this cell but other cells.
+ HSSFCellStyle cellStyle = wb.createCellStyle();
+ cellStyle.setDataFormat(HSSFDataFormat.getBuiltinFormat("m/d/yy h:mm"));
+ cell = row.createCell(1);
+ cell.setCellValue(new Date());
+ cell.setCellStyle(cellStyle);
+
+ // Write the output to a file
+ try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/EmbeddedObjects.java b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/EmbeddedObjects.java
new file mode 100644
index 0000000000..149c908fac
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/EmbeddedObjects.java
@@ -0,0 +1,78 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.hssf.usermodel;
+
+import java.io.Closeable;
+import java.io.FileInputStream;
+
+import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+import org.apache.poi.hssf.usermodel.HSSFObjectData;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hwpf.HWPFDocument;
+import org.apache.poi.poifs.filesystem.DirectoryNode;
+import org.apache.poi.poifs.filesystem.Entry;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+
+/**
+ * Demonstrates how you can extract embedded data from a .xls file
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class EmbeddedObjects {
+ private EmbeddedObjects() {}
+
+ @SuppressWarnings("unused")
+ public static void main(String[] args) throws Exception {
+ try (
+ FileInputStream fis = new FileInputStream(args[0]);
+ POIFSFileSystem fs = new POIFSFileSystem(fis);
+ HSSFWorkbook workbook = new HSSFWorkbook(fs)
+ ) {
+ for (HSSFObjectData obj : workbook.getAllEmbeddedObjects()) {
+ //the OLE2 Class Name of the object
+ String oleName = obj.getOLE2ClassName();
+ DirectoryNode dn = (obj.hasDirectoryEntry()) ? (DirectoryNode) obj.getDirectory() : null;
+ Closeable document = null;
+ switch (oleName) {
+ case "Worksheet":
+ document = new HSSFWorkbook(dn, fs, false);
+ break;
+ case "Document":
+ document = new HWPFDocument(dn);
+ break;
+ case "Presentation":
+ document = new HSLFSlideShow(dn);
+ break;
+ default:
+ if (dn != null) {
+ // The DirectoryEntry is a DocumentNode. Examine its entries to find out what it is
+ for (Entry entry : dn) {
+ String name = entry.getName();
+ }
+ } else {
+ // There is no DirectoryEntry
+ // Recover the object's data from the HSSFObjectData instance.
+ byte[] objectData = obj.getObjectData();
+ }
+ break;
+ }
+ if (document != null) {
+ document.close();
+ }
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/EventExample.java b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/EventExample.java
new file mode 100644
index 0000000000..0e71406b58
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/EventExample.java
@@ -0,0 +1,122 @@
+
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hssf.usermodel;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.poi.hssf.eventusermodel.HSSFEventFactory;
+import org.apache.poi.hssf.eventusermodel.HSSFListener;
+import org.apache.poi.hssf.eventusermodel.HSSFRequest;
+import org.apache.poi.hssf.record.BOFRecord;
+import org.apache.poi.hssf.record.BoundSheetRecord;
+import org.apache.poi.hssf.record.LabelSSTRecord;
+import org.apache.poi.hssf.record.NumberRecord;
+import org.apache.poi.hssf.record.RowRecord;
+import org.apache.poi.hssf.record.SSTRecord;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+
+/**
+ * This example shows how to use the event API for reading a file.
+ */
+@SuppressWarnings({"java:S106","java:S4823"})
+public class EventExample implements HSSFListener {
+ private SSTRecord sstrec;
+
+ /**
+ * This method listens for incoming records and handles them as required.
+ * @param record The record that was found while reading.
+ */
+ @Override
+ public void processRecord(org.apache.poi.hssf.record.Record record)
+ {
+ switch (record.getSid())
+ {
+ // the BOFRecord can represent either the beginning of a sheet or the workbook
+ case BOFRecord.sid:
+ BOFRecord bof = (BOFRecord) record;
+ if (bof.getType() == BOFRecord.TYPE_WORKBOOK)
+ {
+ System.out.println("Encountered workbook");
+ // assigned to the class level member
+ } else if (bof.getType() == BOFRecord.TYPE_WORKSHEET)
+ {
+ System.out.println("Encountered sheet reference");
+ }
+ break;
+ case BoundSheetRecord.sid:
+ BoundSheetRecord bsr = (BoundSheetRecord) record;
+ System.out.println("New sheet named: " + bsr.getSheetname());
+ break;
+ case RowRecord.sid:
+ RowRecord rowrec = (RowRecord) record;
+ System.out.println("Row found, first column at "
+ + rowrec.getFirstCol() + " last column at " + rowrec.getLastCol());
+ break;
+ case NumberRecord.sid:
+ NumberRecord numrec = (NumberRecord) record;
+ System.out.println("Cell found with value " + numrec.getValue()
+ + " at row " + numrec.getRow() + " and column " + numrec.getColumn());
+ break;
+ // SSTRecords store a array of unique strings used in Excel.
+ case SSTRecord.sid:
+ sstrec = (SSTRecord) record;
+ for (int k = 0; k < sstrec.getNumUniqueStrings(); k++)
+ {
+ System.out.println("String table value " + k + " = " + sstrec.getString(k));
+ }
+ break;
+ case LabelSSTRecord.sid:
+ LabelSSTRecord lrec = (LabelSSTRecord) record;
+ System.out.println("String cell found with value "
+ + sstrec.getString(lrec.getSSTIndex()));
+ break;
+ }
+ }
+
+ /**
+ * Read an excel file and spit out what we find.
+ *
+ * @param args Expect one argument that is the file to read.
+ * @throws IOException When there is an error processing the file.
+ */
+ public static void main(String[] args) throws IOException
+ {
+ // create a new file input stream with the input file specified
+ // at the command line
+ try (FileInputStream fin = new FileInputStream(args[0])) {
+ // create a new org.apache.poi.poifs.filesystem.Filesystem
+ try (POIFSFileSystem poifs = new POIFSFileSystem(fin)) {
+ // get the Workbook (excel part) stream in a InputStream
+ try (InputStream din = poifs.createDocumentInputStream("Workbook")) {
+ // construct out HSSFRequest object
+ HSSFRequest req = new HSSFRequest();
+ // lazy listen for ALL records with the listener shown above
+ req.addListenerForAllRecords(new EventExample());
+ // create our event factory
+ HSSFEventFactory factory = new HSSFEventFactory();
+ // process our events based on the document input stream
+ factory.processEvents(req, din);
+ }
+ }
+ }
+ System.out.println("done.");
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/FrillsAndFills.java b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/FrillsAndFills.java
new file mode 100644
index 0000000000..ca2a61e41e
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/FrillsAndFills.java
@@ -0,0 +1,64 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFCellStyle;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined;
+import org.apache.poi.ss.usermodel.FillPatternType;
+
+/**
+ * Shows how to use various fills.
+ */
+public class FrillsAndFills {
+ public static void main(String[] args) throws IOException {
+ try (HSSFWorkbook wb = new HSSFWorkbook()) {
+ HSSFSheet sheet = wb.createSheet("new sheet");
+
+ // Create a row and put some cells in it. Rows are 0 based.
+ HSSFRow row = sheet.createRow(1);
+
+ // Aqua background
+ HSSFCellStyle style = wb.createCellStyle();
+ style.setFillBackgroundColor(HSSFColorPredefined.AQUA.getIndex());
+ style.setFillPattern(FillPatternType.BIG_SPOTS);
+ HSSFCell cell = row.createCell(1);
+ cell.setCellValue("X");
+ cell.setCellStyle(style);
+
+ // Orange "foreground", foreground being the fill foreground not the font color.
+ style = wb.createCellStyle();
+ style.setFillForegroundColor(HSSFColorPredefined.ORANGE.getIndex());
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+ cell = row.createCell(2);
+ cell.setCellValue("X");
+ cell.setCellStyle(style);
+
+ // Write the output to a file
+ try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/HSSFReadWrite.java b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/HSSFReadWrite.java
new file mode 100644
index 0000000000..f53065de94
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/HSSFReadWrite.java
@@ -0,0 +1,251 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hssf.usermodel;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFCellStyle;
+import org.apache.poi.hssf.usermodel.HSSFDataFormat;
+import org.apache.poi.hssf.usermodel.HSSFFont;
+import org.apache.poi.hssf.usermodel.HSSFRichTextString;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.util.CellRangeAddress;
+
+/**
+ * File for HSSF testing/examples
+ *
+ * THIS IS NOT THE MAIN HSSF FILE!! This is a utility for testing functionality.
+ * It does contain sample API usage that may be educational to regular API
+ * users.
+ */
+@SuppressWarnings({"java:S106","java:S4823"})
+public final class HSSFReadWrite {
+
+ private HSSFReadWrite() {}
+
+ /**
+ * creates an {@link HSSFWorkbook} with the specified OS filename.
+ */
+ private static HSSFWorkbook readFile(String filename) throws IOException {
+ try (FileInputStream fis = new FileInputStream(filename)) {
+ return new HSSFWorkbook(fis); // NOSONAR - should not be closed here
+ }
+ }
+
+ /**
+ * given a filename this outputs a sample sheet with just a set of
+ * rows/cells.
+ */
+ private static void testCreateSampleSheet(String outputFilename) throws IOException {
+ try (HSSFWorkbook wb = new HSSFWorkbook();
+ FileOutputStream out = new FileOutputStream(outputFilename)) {
+ HSSFSheet s = wb.createSheet();
+ HSSFCellStyle cs = wb.createCellStyle();
+ HSSFCellStyle cs2 = wb.createCellStyle();
+ HSSFCellStyle cs3 = wb.createCellStyle();
+ HSSFFont f = wb.createFont();
+ HSSFFont f2 = wb.createFont();
+
+ f.setFontHeightInPoints((short) 12);
+ f.setColor((short) 0xA);
+ f.setBold(true);
+ f2.setFontHeightInPoints((short) 10);
+ f2.setColor((short) 0xf);
+ f2.setBold(true);
+ cs.setFont(f);
+ cs.setDataFormat(HSSFDataFormat.getBuiltinFormat("($#,##0_);[Red]($#,##0)"));
+ cs2.setBorderBottom(BorderStyle.THIN);
+ cs2.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+ cs2.setFillForegroundColor((short) 0xA);
+ cs2.setFont(f2);
+ wb.setSheetName(0, "HSSF Test");
+ int rownum;
+ for (rownum = 0; rownum < 300; rownum++) {
+ HSSFRow r = s.createRow(rownum);
+ if ((rownum % 2) == 0) {
+ r.setHeight((short) 0x249);
+ }
+
+ for (int cellnum = 0; cellnum < 50; cellnum += 2) {
+ HSSFCell c = r.createCell(cellnum);
+ c.setCellValue((rownum * 10000.0) + cellnum
+ + (rownum / 1000.0) + (cellnum / 10000.0));
+ if ((rownum % 2) == 0) {
+ c.setCellStyle(cs);
+ }
+ c = r.createCell(cellnum + 1);
+ c.setCellValue(new HSSFRichTextString("TEST"));
+ // 50 characters divided by 1/20th of a point
+ s.setColumnWidth(cellnum + 1, (int) (50 * 8 / 0.05));
+ if ((rownum % 2) == 0) {
+ c.setCellStyle(cs2);
+ }
+ }
+ }
+
+ // draw a thick black border on the row at the bottom using BLANKS
+ rownum++;
+ rownum++;
+ HSSFRow r = s.createRow(rownum);
+ cs3.setBorderBottom(BorderStyle.THICK);
+ for (int cellnum = 0; cellnum < 50; cellnum++) {
+ HSSFCell c = r.createCell(cellnum);
+ c.setCellStyle(cs3);
+ }
+ s.addMergedRegion(new CellRangeAddress(0, 3, 0, 3));
+ s.addMergedRegion(new CellRangeAddress(100, 110, 100, 110));
+
+ // end draw thick black border
+ // create a sheet, set its title then delete it
+ wb.createSheet();
+ wb.setSheetName(1, "DeletedSheet");
+ wb.removeSheetAt(1);
+
+ // end deleted sheet
+ wb.write(out);
+ }
+ }
+
+ /**
+ * Method main
+ *
+ * Given 1 argument takes that as the filename, inputs it and dumps the
+ * cell values/types out to sys.out.<br>
+ *
+ * given 2 arguments where the second argument is the word "write" and the
+ * first is the filename - writes out a sample (test) spreadsheet
+ * see {@link HSSFReadWrite#testCreateSampleSheet(String)}.<br>
+ *
+ * given 2 arguments where the first is an input filename and the second
+ * an output filename (not write), attempts to fully read in the
+ * spreadsheet and fully write it out.<br>
+ *
+ * given 3 arguments where the first is an input filename and the second an
+ * output filename (not write) and the third is "modify1", attempts to read in the
+ * spreadsheet, deletes rows 0-24, 74-99. Changes cell at row 39, col 3 to
+ * "MODIFIED CELL" then writes it out. Hence this is "modify test 1". If you
+ * take the output from the write test, you'll have a valid scenario.
+ */
+ public static void main(String[] args) throws Exception {
+ if (args.length < 1) {
+ System.err.println("At least one argument expected");
+ return;
+ }
+
+ String fileName = args[0];
+ if (args.length < 2) {
+
+ try (HSSFWorkbook wb = HSSFReadWrite.readFile(fileName)) {
+ System.out.println("Data dump:\n");
+
+ for (int k = 0; k < wb.getNumberOfSheets(); k++) {
+ HSSFSheet sheet = wb.getSheetAt(k);
+ int rows = sheet.getPhysicalNumberOfRows();
+ System.out.println("Sheet " + k + " \"" + wb.getSheetName(k) + "\" has " + rows + " row(s).");
+ for (int r = 0; r < rows; r++) {
+ HSSFRow row = sheet.getRow(r);
+ if (row == null) {
+ continue;
+ }
+
+ System.out.println("\nROW " + row.getRowNum() + " has " + row.getPhysicalNumberOfCells() + " cell(s).");
+ for (int c = 0; c < row.getLastCellNum(); c++) {
+ HSSFCell cell = row.getCell(c);
+ String value;
+
+ if (cell != null) {
+ switch (cell.getCellType()) {
+
+ case FORMULA:
+ value = "FORMULA value=" + cell.getCellFormula();
+ break;
+
+ case NUMERIC:
+ value = "NUMERIC value=" + cell.getNumericCellValue();
+ break;
+
+ case STRING:
+ value = "STRING value=" + cell.getStringCellValue();
+ break;
+
+ case BLANK:
+ value = "<BLANK>";
+ break;
+
+ case BOOLEAN:
+ value = "BOOLEAN value-" + cell.getBooleanCellValue();
+ break;
+
+ case ERROR:
+ value = "ERROR value=" + cell.getErrorCellValue();
+ break;
+
+ default:
+ value = "UNKNOWN value of type " + cell.getCellType();
+ }
+ System.out.println("CELL col=" + cell.getColumnIndex() + " VALUE=" + value);
+ }
+ }
+ }
+ }
+ }
+ } else if (args.length == 2) {
+ if ("write".equalsIgnoreCase(args[1])) {
+ System.out.println("Write mode");
+ long time = System.currentTimeMillis();
+ HSSFReadWrite.testCreateSampleSheet(fileName);
+
+ System.out.println("" + (System.currentTimeMillis() - time) + " ms generation time");
+ } else {
+ System.out.println("readwrite test");
+ try (HSSFWorkbook wb = HSSFReadWrite.readFile(fileName);
+ FileOutputStream stream = new FileOutputStream(args[1])) {
+ wb.write(stream);
+ }
+ }
+ } else if (args.length == 3 && "modify1".equalsIgnoreCase(args[2])) {
+ // delete row 0-24, row 74 - 99 && change cell 3 on row 39 to string "MODIFIED CELL!!"
+
+ try (HSSFWorkbook wb = HSSFReadWrite.readFile(fileName);
+ FileOutputStream stream = new FileOutputStream(args[1])) {
+ HSSFSheet sheet = wb.getSheetAt(0);
+
+ for (int k = 0; k < 25; k++) {
+ HSSFRow row = sheet.getRow(k);
+ sheet.removeRow(row);
+ }
+ for (int k = 74; k < 100; k++) {
+ HSSFRow row = sheet.getRow(k);
+ sheet.removeRow(row);
+ }
+ HSSFRow row = sheet.getRow(39);
+ HSSFCell cell = row.getCell(3);
+ cell.setCellValue("MODIFIED CELL!!!!!");
+
+ wb.write(stream);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/HyperlinkFormula.java b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/HyperlinkFormula.java
new file mode 100644
index 0000000000..96fa30a90f
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/HyperlinkFormula.java
@@ -0,0 +1,45 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+
+/**
+ * Test if hyperlink formula, with url that got more than 127 characters, works
+ */
+public class HyperlinkFormula {
+ public static void main(String[] args) throws IOException {
+ try (HSSFWorkbook wb = new HSSFWorkbook()) {
+ HSSFSheet sheet = wb.createSheet("new sheet");
+ HSSFRow row = sheet.createRow(0);
+
+ HSSFCell cell = row.createCell(0);
+ cell.setCellFormula("HYPERLINK(\"http://127.0.0.1:8080/toto/truc/index.html?test=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\", \"test\")");
+
+ try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/Hyperlinks.java b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/Hyperlinks.java
new file mode 100644
index 0000000000..ae4a37ea13
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/Hyperlinks.java
@@ -0,0 +1,97 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.common.usermodel.HyperlinkType;
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFCellStyle;
+import org.apache.poi.hssf.usermodel.HSSFCreationHelper;
+import org.apache.poi.hssf.usermodel.HSSFFont;
+import org.apache.poi.hssf.usermodel.HSSFHyperlink;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined;
+import org.apache.poi.ss.usermodel.Font;
+
+/**
+ * Demonstrates how to create hyperlinks.
+ */
+public class Hyperlinks {
+
+ public static void main(String[] args) throws IOException {
+ try (HSSFWorkbook wb = new HSSFWorkbook()) {
+ HSSFCreationHelper helper = wb.getCreationHelper();
+
+ //cell style for hyperlinks
+ //by default hyperlinks are blue and underlined
+ HSSFCellStyle hlinkStyle = wb.createCellStyle();
+ HSSFFont hlinkFont = wb.createFont();
+ hlinkFont.setUnderline(Font.U_SINGLE);
+ hlinkFont.setColor(HSSFColorPredefined.BLUE.getIndex());
+ hlinkStyle.setFont(hlinkFont);
+
+ HSSFCell cell;
+ HSSFSheet sheet = wb.createSheet("Hyperlinks");
+
+ //URL
+ cell = sheet.createRow(0).createCell(0);
+ cell.setCellValue("URL Link");
+ HSSFHyperlink link = helper.createHyperlink(HyperlinkType.URL);
+ link.setAddress("https://poi.apache.org/");
+ cell.setHyperlink(link);
+ cell.setCellStyle(hlinkStyle);
+
+ //link to a file in the current directory
+ cell = sheet.createRow(1).createCell(0);
+ cell.setCellValue("File Link");
+ link = helper.createHyperlink(HyperlinkType.FILE);
+ link.setAddress("link1.xls");
+ cell.setHyperlink(link);
+ cell.setCellStyle(hlinkStyle);
+
+ //e-mail link
+ cell = sheet.createRow(2).createCell(0);
+ cell.setCellValue("Email Link");
+ link = helper.createHyperlink(HyperlinkType.EMAIL);
+ //note, if subject contains white spaces, make sure they are url-encoded
+ link.setAddress("mailto:poi@apache.org?subject=Hyperlinks");
+ cell.setHyperlink(link);
+ cell.setCellStyle(hlinkStyle);
+
+ //link to a place in this workbook
+
+ //create a target sheet and cell
+ HSSFSheet sheet2 = wb.createSheet("Target Sheet");
+ sheet2.createRow(0).createCell(0).setCellValue("Target Cell");
+
+ cell = sheet.createRow(3).createCell(0);
+ cell.setCellValue("Worksheet Link");
+ link = helper.createHyperlink(HyperlinkType.DOCUMENT);
+ link.setAddress("'Target Sheet'!A1");
+ cell.setHyperlink(link);
+ cell.setCellStyle(hlinkStyle);
+
+ try (FileOutputStream out = new FileOutputStream("hssf-links.xls")) {
+ wb.write(out);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/InCellLists.java b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/InCellLists.java
new file mode 100644
index 0000000000..76d0172f82
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/InCellLists.java
@@ -0,0 +1,541 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+
+package org.apache.poi.examples.hssf.usermodel;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFCellStyle;
+import org.apache.poi.hssf.usermodel.HSSFDataFormat;
+import org.apache.poi.hssf.usermodel.HSSFRichTextString;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+
+/**
+ * This class contains code that demonstrates how to insert plain, numbered
+ * and bulleted lists into an Excel spreadsheet cell.
+ *
+ * Look at the code contained in the demonstrateMethodCalls() method. It calls
+ * other methods that create plain, numbered and bulleted single and
+ * multi-level lists. The demonstrateMethodCalls() method appears at the top
+ * of the class definition.
+ *
+ * Though different methods are provided to construct single and multi-level
+ * plain, numbered and bulleted lists, close examination will reveal that they
+ * are not strictly necessary. If the inputs to the listInCell() and
+ * multilLevelListInCell() methods are constructed to include the bullet
+ * character or the item numbers then these methods alone may be sufficient.
+ *
+ * @author Mark Beardsley [msb at apache.org]
+ */
+@SuppressWarnings({"java:S106","java:S4823"})
+public class InCellLists {
+
+ // This character looks like a solid, black, loser case letter 'o'
+ // positioned up from the base line of the text.
+ private static final char BULLET_CHARACTER = '\u2022';
+
+ // The tab character - \t - cannot be used to create a tab space
+ // within a cell as it is rendered as a square. Therefore, four
+ // spaces are used to simulate that character.
+ private static final String TAB = " ";
+
+ /**
+ * Call each of the list creation methods.
+ *
+ * @param outputFilename A String that encapsulates the name of and path to
+ * the Excel spreadsheet file this code will create.
+ */
+ public void demonstrateMethodCalls(String outputFilename) throws IOException {
+ try (HSSFWorkbook workbook = new HSSFWorkbook()) {
+ HSSFSheet sheet = workbook.createSheet("In Cell Lists");
+ HSSFRow row = sheet.createRow(0);
+
+ // Create a cell at A1 and insert a single, bulleted, item into
+ // that cell.
+ HSSFCell cell = row.createCell(0);
+ this.bulletedItemInCell(workbook, "List Item", cell);
+
+ // Create a cell at A2 and insert a plain list - that is one
+ // whose items are neither bulleted or numbered - into that cell.
+ row = sheet.createRow(1);
+ cell = row.createCell(0);
+ List<String> listItems = new ArrayList<>();
+ listItems.add("List Item One.");
+ listItems.add("List Item Two.");
+ listItems.add("List Item Three.");
+ listItems.add("List Item Four.");
+ this.listInCell(workbook, listItems, cell);
+ // The row height and cell width are set here to ensure that the
+ // list may be seen.
+ row.setHeight((short) 1100);
+ sheet.setColumnWidth(0, 9500);
+
+ // Create a cell at A3 and insert a numbered list into that cell.
+ // Note that a couple of items have been added to the listItems
+ // ArrayList
+ row = sheet.createRow(2);
+ cell = row.createCell(0);
+ listItems.add("List Item Five.");
+ listItems.add("List Item Six.");
+ this.numberedListInCell(workbook, listItems, cell, 1, 2);
+ row.setHeight((short) 1550);
+
+ // Create a cell at A4 and insert a numbered list into that cell.
+ // Note that a couple of items have been added to the listItems
+ // ArrayList
+ row = sheet.createRow(3);
+ cell = row.createCell(0);
+ listItems.add("List Item Seven.");
+ listItems.add("List Item Eight.");
+ listItems.add("List Item Nine.");
+ listItems.add("List Item Ten.");
+ this.bulletedListInCell(workbook, listItems, cell);
+ row.setHeight((short) 2550);
+
+ // Insert a plain, multi-level list into cell A5. Note that
+ // the major difference here is that the list items are passed as
+ // an ArrayList of MultiLevelListItems. Note that an ArrayList
+ // of instances of an inner class was used here in preference to
+ // a Hashtable or HashMap as the ArrayList will preserve the
+ // ordering of the items added to it; the first item added will
+ // be the first item recovered and the last item added, the last
+ // item recovered. Alternatively, a LinkedHashMap could be used
+ // to preserve order.
+ row = sheet.createRow(4);
+ cell = row.createCell(0);
+ List<MultiLevelListItem> multiLevelListItems = new ArrayList<>();
+ listItems = new ArrayList<>();
+ listItems.add("ML List Item One - Sub Item One.");
+ listItems.add("ML List Item One - Sub Item Two.");
+ listItems.add("ML List Item One - Sub Item Three.");
+ listItems.add("ML List Item One - Sub Item Four.");
+ multiLevelListItems.add(new MultiLevelListItem("List Item One.", listItems));
+ // Passing either null or an empty ArrayList will signal that
+ // there are no lower level items associated with the top level
+ // item
+ multiLevelListItems.add(new MultiLevelListItem("List Item Two.", null));
+ multiLevelListItems.add(new MultiLevelListItem("List Item Three.", null));
+ listItems = new ArrayList<>();
+ listItems.add("ML List Item Four - Sub Item One.");
+ listItems.add("ML List Item Four - Sub Item Two.");
+ listItems.add("ML List Item Four - Sub Item Three.");
+ multiLevelListItems.add(new MultiLevelListItem("List Item Four.", listItems));
+ this.multiLevelListInCell(workbook, multiLevelListItems, cell);
+ row.setHeight((short) 2800);
+
+ // Insert a numbered multi-level list into cell A6. Note that the
+ // same ArrayList as constructed for the above plain multi-level
+ // list example will be re-used
+ row = sheet.createRow(5);
+ cell = row.createCell(0);
+ this.multiLevelNumberedListInCell(workbook, multiLevelListItems,
+ cell, 1, 1, 1, 2);
+ row.setHeight((short) 2800);
+
+ // Insert a numbered multi-level list into cell A7. Note that the
+ // same ArrayList as constructed for the plain multi-level list
+ // example will be re-used
+ row = sheet.createRow(6);
+ cell = row.createCell(0);
+ this.multiLevelBulletedListInCell(workbook, multiLevelListItems, cell);
+ row.setHeight((short) 2800);
+
+ // Save the completed workbook
+ try (FileOutputStream fos = new FileOutputStream(new File(outputFilename))) {
+ workbook.write(fos);
+ }
+ } catch (IOException ioEx) {
+ System.out.println("Caught a: " + ioEx.getClass().getName());
+ System.out.println("Message: " + ioEx.getMessage());
+ System.out.println("Stacktrace follows...........");
+ ioEx.printStackTrace(System.out);
+ }
+ }
+
+ /**
+ * Inserts a single bulleted item into a cell.
+ *
+ * @param workbook A reference to the HSSFWorkbook that 'contains' the
+ * cell.
+ * @param listItem An instance of the String class encapsulating the
+ * items text.
+ * @param cell An instance of the HSSFCell class that encapsulates a
+ * reference to the spreadsheet cell into which the list item
+ * will be written.
+ */
+ public void bulletedItemInCell(HSSFWorkbook workbook, String listItem, HSSFCell cell) {
+ // A format String must be built to ensure that the contents of the
+ // cell appear as a bulleted item.
+ HSSFDataFormat format = workbook.createDataFormat();
+ String formatString = InCellLists.BULLET_CHARACTER + " @";
+ int formatIndex = format.getFormat(formatString);
+
+ // Construct an HSSFCellStyle and set it's data formt to use the
+ // object created above.
+ HSSFCellStyle bulletStyle = workbook.createCellStyle();
+ bulletStyle.setDataFormat((short)formatIndex);
+
+ // Set the cells contents and style.
+ cell.setCellValue(new HSSFRichTextString(listItem));
+ cell.setCellStyle(bulletStyle);
+ }
+
+ /**
+ * Inserts a list of plain items - that is items that are neither
+ * numbered or bulleted - into a single cell.
+ *
+ * @param workbook A reference to the HSSFWorkbook that 'contains' the
+ * cell.
+ * @param listItems An ArrayList whose elements encapsulate the text for
+ * the list's items.
+ * @param cell An instance of the HSSFCell class that encapsulates a
+ * reference to the spreadsheet cell into which the list
+ * will be written.
+ */
+ public void listInCell(HSSFWorkbook workbook, List<String> listItems, HSSFCell cell) {
+ StringBuilder buffer = new StringBuilder();
+ HSSFCellStyle wrapStyle = workbook.createCellStyle();
+ wrapStyle.setWrapText(true);
+ for(String listItem : listItems) {
+ buffer.append(listItem);
+ buffer.append("\n");
+ }
+ // The StringBuilder's contents are the source for the contents
+ // of the cell.
+ cell.setCellValue(new HSSFRichTextString(buffer.toString().trim()));
+ cell.setCellStyle(wrapStyle);
+ }
+
+ /**
+ * Inserts a numbered list into a single cell.
+ *
+ * @param workbook A reference to the HSSFWorkbook that 'contains' the
+ * cell.
+ * @param listItems An ArrayList whose elements encapsulate the text for
+ * the lists items.
+ * @param cell An instance of the HSSFCell class that encapsulates a
+ * reference to the spreadsheet cell into which the list
+ * will be written.
+ * @param startingValue A primitive int containing the number for the first
+ * item in the list.
+ * @param increment A primitive int containing the value that should be used
+ * to calculate subsequent item numbers.
+ */
+ public void numberedListInCell(HSSFWorkbook workbook,
+ List<String> listItems,
+ HSSFCell cell,
+ int startingValue,
+ int increment) {
+ StringBuilder buffer = new StringBuilder();
+ int itemNumber = startingValue;
+ // Note that again, an HSSFCellStye object is required and that
+ // it's wrap text property should be set to 'true'
+ HSSFCellStyle wrapStyle = workbook.createCellStyle();
+ wrapStyle.setWrapText(true);
+ // Note that the basic method is identical to the listInCell() method
+ // with one difference; a number prefixed to the items text.
+ for(String listItem : listItems) {
+ buffer.append(itemNumber).append(". ");
+ buffer.append(listItem);
+ buffer.append("\n");
+ itemNumber += increment;
+ }
+ // The StringBuilder's contents are the source for the contents
+ // of the cell.
+ cell.setCellValue(new HSSFRichTextString(buffer.toString().trim()));
+ cell.setCellStyle(wrapStyle);
+ }
+
+ /**
+ * Insert a bulleted list into a cell.
+ *
+ * @param workbook A reference to the HSSFWorkbook that 'contains' the
+ * cell.
+ * @param listItems An ArrayList whose elements encapsulate the text for
+ * the lists items.
+ * @param cell An instance of the HSSFCell class that encapsulates a
+ * reference to the spreadsheet cell into which the list
+ * will be written.
+ */
+ public void bulletedListInCell(HSSFWorkbook workbook,
+ List<String> listItems,
+ HSSFCell cell) {
+ StringBuilder buffer = new StringBuilder();
+ // Note that again, an HSSFCellStye object is required and that
+ // it's wrap text property should be set to 'true'
+ HSSFCellStyle wrapStyle = workbook.createCellStyle();
+ wrapStyle.setWrapText(true);
+ // Note that the basic method is identical to the listInCell() method
+ // with one difference; the bullet character prefixed to the items text.
+ for(String listItem : listItems) {
+ buffer.append(InCellLists.BULLET_CHARACTER + " ");
+ buffer.append(listItem);
+ buffer.append("\n");
+ }
+ // The StringBuilder's contents are the source for the contents
+ // of the cell.
+ cell.setCellValue(new HSSFRichTextString(buffer.toString().trim()));
+ cell.setCellStyle(wrapStyle);
+ }
+
+ /**
+ * Insert a multi-level list into a cell.
+ *
+ * @param workbook A reference to the HSSFWorkbook that 'contains' the
+ * cell.
+ * @param multiLevelListItems An ArrayList whose elements contain instances
+ * of the MultiLevelListItem class. Each element
+ * encapsulates the text for the high level item
+ * along with an ArrayList. Each element of this
+ * ArrayList encapsulates the text for a lower
+ * level item.
+ * @param cell An instance of the HSSFCell class that encapsulates a
+ * reference to the spreadsheet cell into which the list
+ * will be written.
+ */
+ public void multiLevelListInCell(HSSFWorkbook workbook,
+ List<MultiLevelListItem> multiLevelListItems,
+ HSSFCell cell) {
+ StringBuilder buffer = new StringBuilder();
+ // Note that again, an HSSFCellStye object is required and that
+ // it's wrap text property should be set to 'true'
+ HSSFCellStyle wrapStyle = workbook.createCellStyle();
+ wrapStyle.setWrapText(true);
+ // Step through the ArrayList of MultilLevelListItem instances.
+ for(MultiLevelListItem multiLevelListItem : multiLevelListItems) {
+ // For each element in the ArrayList, get the text for the high
+ // level list item......
+ buffer.append(multiLevelListItem.getItemText());
+ buffer.append("\n");
+ // and then an ArrayList whose elements encapsulate the text
+ // for the lower level list items.
+ List<String> lowerLevelItems = multiLevelListItem.getLowerLevelItems();
+ if (lowerLevelItems == null || lowerLevelItems.isEmpty()) {
+ continue;
+ }
+ for(String item : lowerLevelItems) {
+ buffer.append(InCellLists.TAB);
+ buffer.append(item);
+ buffer.append("\n");
+ }
+ }
+ // The StringBuilder's contents are the source for the contents
+ // of the cell.
+ cell.setCellValue(new HSSFRichTextString(buffer.toString().trim()));
+ cell.setCellStyle(wrapStyle);
+ }
+
+ /**
+ * Insert a multi-level list into a cell.
+ *
+ * @param workbook A reference to the HSSFWorkbook that 'contains' the
+ * cell.
+ * @param multiLevelListItems An ArrayList whose elements contain instances
+ * of the MultiLevelListItem class. Each element
+ * encapsulates the text for the high level item
+ * along with an ArrayList. Each element of this
+ * ArrayList encapsulates the text for a lower
+ * level item.
+ * @param cell An instance of the HSSFCell class that encapsulates a
+ * reference to the spreadsheet cell into which the list
+ * will be written.
+ * @param highLevelStartingValue A primitive int containing the number
+ * for the first high level item in the list.
+ * @param highLevelIncrement A primitive int containing the value that
+ * should be used to calculate the number of
+ * subsequent high level item.
+ * @param lowLevelStartingValue A primitive int will containing the number
+ * for the first low level item associated
+ * with a high level item.
+ * @param lowLevelIncrement A primitive int containing the value that
+ * should be used to calculate the number of
+ * subsequent low level item.
+ */
+ public void multiLevelNumberedListInCell(HSSFWorkbook workbook,
+ List<MultiLevelListItem> multiLevelListItems,
+ HSSFCell cell,
+ int highLevelStartingValue,
+ int highLevelIncrement,
+ int lowLevelStartingValue,
+ int lowLevelIncrement) {
+ StringBuilder buffer = new StringBuilder();
+ int highLevelItemNumber = highLevelStartingValue;
+ // Note that again, an HSSFCellStye object is required and that
+ // it's wrap text property should be set to 'true'
+ HSSFCellStyle wrapStyle = workbook.createCellStyle();
+ wrapStyle.setWrapText(true);
+ // Step through the ArrayList of MultilLevelListItem instances.
+ for(MultiLevelListItem multiLevelListItem : multiLevelListItems) {
+ // For each element in the ArrayList, get the text for the high
+ // level list item......
+ buffer.append(highLevelItemNumber);
+ buffer.append(". ");
+ buffer.append(multiLevelListItem.getItemText());
+ buffer.append("\n");
+ // and then an ArrayList whose elements encapsulate the text
+ // for the lower level list items.
+ List<String> lowerLevelItems = multiLevelListItem.getLowerLevelItems();
+ if(lowerLevelItems != null && !lowerLevelItems.isEmpty()) {
+ int lowLevelItemNumber = lowLevelStartingValue;
+ for(String item : lowerLevelItems) {
+ buffer.append(InCellLists.TAB);
+ buffer.append(highLevelItemNumber);
+ buffer.append(".");
+ buffer.append(lowLevelItemNumber);
+ buffer.append(" ");
+ buffer.append(item);
+ buffer.append("\n");
+ lowLevelItemNumber += lowLevelIncrement;
+ }
+ }
+ highLevelItemNumber += highLevelIncrement;
+ }
+ // The StringBuilder's contents are the source for the contents
+ // of the cell.
+ cell.setCellValue(new HSSFRichTextString(buffer.toString().trim()));
+ cell.setCellStyle(wrapStyle);
+ }
+
+ /**
+ * Insert a bulleted multi-level list into a cell.
+ *
+ * @param workbook A reference to the HSSFWorkbook that 'contains' the
+ * cell.
+ * @param multiLevelListItems An ArrayList whose elements contain instances
+ * of the MultiLevelListItem class. Each element
+ * encapsulates the text for the high level item
+ * along with an ArrayList. Each element of this
+ * ArrayList encapsulates the text for a lower
+ * level item.
+ * @param cell An instance of the HSSFCell class that encapsulates a
+ * reference to the spreadsheet cell into which the list
+ * will be written.
+ */
+ public void multiLevelBulletedListInCell(HSSFWorkbook workbook,
+ List<MultiLevelListItem> multiLevelListItems,
+ HSSFCell cell) {
+ StringBuilder buffer = new StringBuilder();
+ // Note that again, an HSSFCellStye object is required and that
+ // it's wrap text property should be set to 'true'
+ HSSFCellStyle wrapStyle = workbook.createCellStyle();
+ wrapStyle.setWrapText(true);
+ // Step through the ArrayList of MultilLevelListItem instances.
+ for(MultiLevelListItem multiLevelListItem : multiLevelListItems) {
+ // For each element in the ArrayList, get the text for the high
+ // level list item......
+ buffer.append(InCellLists.BULLET_CHARACTER);
+ buffer.append(" ");
+ buffer.append(multiLevelListItem.getItemText());
+ buffer.append("\n");
+ // and then an ArrayList whose elements encapsulate the text
+ // for the lower level list items.
+ List<String> lowerLevelItems = multiLevelListItem.getLowerLevelItems();
+ if(lowerLevelItems != null && !lowerLevelItems.isEmpty()) {
+ for(String item : lowerLevelItems) {
+ buffer.append(InCellLists.TAB);
+ buffer.append(InCellLists.BULLET_CHARACTER);
+ buffer.append(" ");
+ buffer.append(item);
+ buffer.append("\n");
+ }
+ }
+ }
+ // The StringBuilder's contents are the source for the contents
+ // of the cell.
+ cell.setCellValue(new HSSFRichTextString(buffer.toString().trim()));
+ cell.setCellStyle(wrapStyle);
+ }
+
+ /**
+ * The main entry point to the program. Demonstrates how to call the method
+ * that will create an Excel workbook containing many different sorts of
+ * lists.
+ *
+ * @param args the command line arguments.
+ */
+ public static void main(String[] args) throws IOException {
+ new InCellLists().demonstrateMethodCalls("Latest In Cell List.xls");
+ }
+
+ /**
+ * An instance of this inner class models an item or element in a
+ * multi-level list. Each multi-level list item consists of the text for the
+ * high level items and an ArrayList containing the text for each of the
+ * associated lower level items. When written into a cell, each multi-level
+ * list item will have this general appearance.
+ *
+ * Item One
+ * Sub Item One.
+ * Sub Item Two.
+ * Item Two
+ * Sub Item One.
+ * Sub Item Two.
+ * etc.
+ *
+ * It would be quite possible to modify this class to model much more
+ * complex list structures descending through two, three or even more
+ * levels.
+ */
+ public final class MultiLevelListItem {
+
+ private String itemText;
+ private List<String> lowerLevelItems;
+
+ /**
+ * Create a new instance of the MultiLevelListItem class using the
+ * following parameters.
+ *
+ * @param itemText A String that encapsulates the text for the high
+ * level list item.
+ * @param lowerLevelItems An ArrayList whose elements encapsulate the
+ * text for the associated lower level list
+ * items.
+ */
+ public MultiLevelListItem(String itemText, List<String> lowerLevelItems) {
+ this.itemText = itemText;
+ this.lowerLevelItems = lowerLevelItems;
+ }
+
+ /**
+ * Get the text for the high level list item.
+ *
+ * @return A String that encapsulates the text for the high level list
+ * item.
+ */
+ public String getItemText() {
+ return(this.itemText);
+ }
+
+ /**
+ * Get the text for the associated lower level list items.
+ *
+ * @return An ArrayList whose elements each encapsulate the text for a
+ * single associated lower level list item.
+ */
+ public List<String> getLowerLevelItems() {
+ return lowerLevelItems;
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/MergedCells.java b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/MergedCells.java
new file mode 100644
index 0000000000..16114b2d63
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/MergedCells.java
@@ -0,0 +1,49 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.util.CellRangeAddress;
+
+/**
+ * An example of how to merge regions of cells.
+ */
+public class MergedCells {
+ public static void main(String[] args) throws IOException {
+ try (HSSFWorkbook wb = new HSSFWorkbook()) {
+ HSSFSheet sheet = wb.createSheet("new sheet");
+
+ HSSFRow row = sheet.createRow(1);
+ HSSFCell cell = row.createCell(1);
+ cell.setCellValue("This is a test of merging");
+
+ sheet.addMergedRegion(new CellRangeAddress(1, 1, 1, 2));
+
+ // Write the output to a file
+ try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/NewLinesInCells.java b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/NewLinesInCells.java
new file mode 100644
index 0000000000..487668da10
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/NewLinesInCells.java
@@ -0,0 +1,57 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFCellStyle;
+import org.apache.poi.hssf.usermodel.HSSFFont;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+
+/**
+ * Demonstrates how to use newlines in cells.
+ */
+public class NewLinesInCells {
+ public static void main( String[] args ) throws IOException {
+ try (HSSFWorkbook wb = new HSSFWorkbook()) {
+ HSSFSheet s = wb.createSheet();
+ HSSFFont f2 = wb.createFont();
+
+ HSSFCellStyle cs = wb.createCellStyle();
+
+ cs.setFont(f2);
+ // Word Wrap MUST be turned on
+ cs.setWrapText(true);
+
+ HSSFRow r = s.createRow(2);
+ r.setHeight((short) 0x349);
+ HSSFCell c = r.createCell(2);
+ c.setCellValue("Use \n with word wrap on to create a new line");
+ c.setCellStyle(cs);
+ s.setColumnWidth(2, (int) ((50 * 8) / ((double) 1 / 20)));
+
+ try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/NewSheet.java b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/NewSheet.java
new file mode 100644
index 0000000000..d2d8f31d0a
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/NewSheet.java
@@ -0,0 +1,44 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.util.WorkbookUtil;
+
+/**
+ * Creates a new workbook with a sheet that's been explicitly defined.
+ */
+public abstract class NewSheet {
+ public static void main(String[] args) throws IOException {
+ try (HSSFWorkbook wb = new HSSFWorkbook()) {
+ wb.createSheet("new sheet");
+ // create with default name
+ wb.createSheet();
+ final String name = "second sheet";
+ // setting sheet name later
+ wb.setSheetName(1, WorkbookUtil.createSafeSheetName(name));
+
+ try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/NewWorkbook.java b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/NewWorkbook.java
new file mode 100644
index 0000000000..16c0e04de1
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/NewWorkbook.java
@@ -0,0 +1,38 @@
+
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+
+package org.apache.poi.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+
+/**
+ * This example creates a new blank workbook. This workbook will contain a single blank sheet.
+ */
+public class NewWorkbook {
+ public static void main(String[] args) throws IOException {
+ try (HSSFWorkbook wb = new HSSFWorkbook()) {
+ try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/OfficeDrawing.java b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/OfficeDrawing.java
new file mode 100644
index 0000000000..4603864d86
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/OfficeDrawing.java
@@ -0,0 +1,330 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hssf.usermodel;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFChildAnchor;
+import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
+import org.apache.poi.hssf.usermodel.HSSFFont;
+import org.apache.poi.hssf.usermodel.HSSFPatriarch;
+import org.apache.poi.hssf.usermodel.HSSFPicture;
+import org.apache.poi.hssf.usermodel.HSSFPolygon;
+import org.apache.poi.hssf.usermodel.HSSFRichTextString;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFShape;
+import org.apache.poi.hssf.usermodel.HSSFShapeGroup;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFSimpleShape;
+import org.apache.poi.hssf.usermodel.HSSFTextbox;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.ClientAnchor.AnchorType;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.Workbook;
+
+/**
+ * Demonstrates how to use the office drawing capabilities of POI.
+ */
+public final class OfficeDrawing {
+ private OfficeDrawing() {}
+
+ public static void main(String[] args) throws IOException {
+ // Create the workbook and sheets.
+ try (HSSFWorkbook wb = new HSSFWorkbook()) {
+ HSSFSheet sheet1 = wb.createSheet("new sheet");
+ HSSFSheet sheet2 = wb.createSheet("second sheet");
+ HSSFSheet sheet3 = wb.createSheet("third sheet");
+ HSSFSheet sheet4 = wb.createSheet("fourth sheet");
+ HSSFSheet sheet5 = wb.createSheet("fifth sheet");
+
+ // Draw stuff in them
+ drawSheet1(sheet1);
+ drawSheet2(sheet2);
+ drawSheet3(sheet3);
+ drawSheet4(sheet4, wb);
+ drawSheet5(sheet5, wb);
+
+ // Write the file out.
+ try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+
+ private static void drawSheet1( HSSFSheet sheet1 )
+ {
+ // Create a row and size one of the cells reasonably large.
+ HSSFRow row = sheet1.createRow(2);
+ row.setHeight((short) 2800);
+ row.createCell(1);
+ sheet1.setColumnWidth(2, 9000);
+
+ // Create the drawing patriarch. This is the top level container for
+ // all shapes.
+ HSSFPatriarch patriarch = sheet1.createDrawingPatriarch();
+
+ // Draw some lines and an oval.
+ drawLinesToCenter( patriarch );
+ drawManyLines( patriarch );
+ drawOval( patriarch );
+ drawPolygon( patriarch );
+
+ // Draw a rectangle.
+ HSSFSimpleShape rect = patriarch.createSimpleShape( new HSSFClientAnchor(100, 100, 900, 200, (short)0, 0, (short)0, 0) );
+ rect.setShapeType(HSSFSimpleShape.OBJECT_TYPE_RECTANGLE);
+ }
+
+ private static void drawSheet2( HSSFSheet sheet2 )
+ {
+ // Create a row and size one of the cells reasonably large.
+ HSSFRow row = sheet2.createRow(2);
+ row.createCell(1);
+ row.setHeightInPoints(240);
+ sheet2.setColumnWidth(2, 9000);
+
+ // Create the drawing patriarch. This is the top level container for
+ // all shapes. This will clear out any existing shapes for that sheet.
+ HSSFPatriarch patriarch = sheet2.createDrawingPatriarch();
+
+ // Draw a grid in one of the cells.
+ drawGrid( patriarch );
+ }
+
+ private static void drawSheet3( HSSFSheet sheet3 )
+ {
+ // Create a row and size one of the cells reasonably large
+ HSSFRow row = sheet3.createRow(2);
+ row.setHeightInPoints(140);
+ row.createCell(1);
+ sheet3.setColumnWidth(2, 9000);
+
+ // Create the drawing patriarch. This is the top level container for
+ // all shapes. This will clear out any existing shapes for that sheet.
+ HSSFPatriarch patriarch = sheet3.createDrawingPatriarch();
+
+ // Create a shape group.
+ HSSFShapeGroup group = patriarch.createGroup(
+ new HSSFClientAnchor(0,0,900,200,(short)2,2,(short)2,2));
+
+ // Create a couple of lines in the group.
+ HSSFSimpleShape shape1 = group.createShape(new HSSFChildAnchor(3,3,500,500));
+ shape1.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
+ ( (HSSFChildAnchor) shape1.getAnchor() ).setAnchor((short)3,3,500,500);
+ HSSFSimpleShape shape2 = group.createShape(new HSSFChildAnchor((short)1,200,400,600));
+ shape2.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
+
+ }
+
+ private static void drawSheet4( HSSFSheet sheet4, HSSFWorkbook wb )
+ {
+ // Create the drawing patriarch. This is the top level container for
+ // all shapes. This will clear out any existing shapes for that sheet.
+ HSSFPatriarch patriarch = sheet4.createDrawingPatriarch();
+
+ // Create a couple of textboxes
+ HSSFTextbox textbox1 = patriarch.createTextbox(
+ new HSSFClientAnchor(0,0,0,0,(short)1,1,(short)2,2));
+ textbox1.setString(new HSSFRichTextString("This is a test") );
+ HSSFTextbox textbox2 = patriarch.createTextbox(
+ new HSSFClientAnchor(0,0,900,100,(short)3,3,(short)3,4));
+ textbox2.setString(new HSSFRichTextString("Woo") );
+ textbox2.setFillColor(200,0,0);
+ textbox2.setLineStyle(HSSFShape.LINESTYLE_DOTGEL);
+
+ // Create third one with some fancy font styling.
+ HSSFTextbox textbox3 = patriarch.createTextbox(
+ new HSSFClientAnchor(0,0,900,100,(short)4,4,(short)5,4+1));
+ HSSFFont font = wb.createFont();
+ font.setItalic(true);
+ font.setUnderline(Font.U_DOUBLE);
+ HSSFRichTextString string = new HSSFRichTextString("Woo!!!");
+ string.applyFont(2,5,font);
+ textbox3.setString(string );
+ textbox3.setFillColor(0x08000030);
+ textbox3.setLineStyle(HSSFShape.LINESTYLE_NONE); // no line around the textbox.
+ textbox3.setNoFill(true); // make it transparent
+ }
+
+ private static void drawSheet5( HSSFSheet sheet5, HSSFWorkbook wb ) throws IOException
+ {
+
+ // Create the drawing patriarch. This is the top level container for
+ // all shapes. This will clear out any existing shapes for that sheet.
+ HSSFPatriarch patriarch = sheet5.createDrawingPatriarch();
+
+ HSSFClientAnchor anchor;
+ anchor = new HSSFClientAnchor(0,0,0,255,(short)2,2,(short)4,7);
+ anchor.setAnchorType( AnchorType.MOVE_DONT_RESIZE );
+ patriarch.createPicture(anchor, loadPicture( "src/resources/logos/logoKarmokar4.png", wb ));
+
+ anchor = new HSSFClientAnchor(0,0,0,255,(short)4,2,(short)5,7);
+ anchor.setAnchorType( AnchorType.MOVE_DONT_RESIZE );
+ patriarch.createPicture(anchor, loadPicture( "src/resources/logos/logoKarmokar4edited.png", wb ));
+
+ anchor = new HSSFClientAnchor(0,0,1023,255,(short)6,2,(short)8,7);
+ anchor.setAnchorType( AnchorType.MOVE_DONT_RESIZE );
+ HSSFPicture picture = patriarch.createPicture(anchor, loadPicture( "src/resources/logos/logoKarmokar4s.png", wb ));
+ //Reset the image to the original size.
+ picture.resize();
+ picture.setLineStyle( HSSFShape.LINESTYLE_DASHDOTGEL );
+
+ }
+
+ private static int loadPicture( String path, HSSFWorkbook wb ) throws IOException
+ {
+ int pictureIndex;
+ try (FileInputStream fis = new FileInputStream(path);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
+ int c;
+ while ((c = fis.read()) != -1)
+ bos.write(c);
+ pictureIndex = wb.addPicture(bos.toByteArray(), Workbook.PICTURE_TYPE_PNG);
+ }
+ return pictureIndex;
+ }
+
+ private static void drawOval( HSSFPatriarch patriarch )
+ {
+ // Create an oval and style to taste.
+ HSSFClientAnchor a = new HSSFClientAnchor();
+ a.setAnchor((short)2, 2, 20, 20, (short) 2, 2, 190, 80);
+ HSSFSimpleShape s = patriarch.createSimpleShape(a);
+ s.setShapeType(HSSFSimpleShape.OBJECT_TYPE_OVAL);
+ s.setLineStyleColor(10,10,10);
+ s.setFillColor(90,10,200);
+ s.setLineWidth(HSSFShape.LINEWIDTH_ONE_PT * 3);
+ s.setLineStyle(HSSFShape.LINESTYLE_DOTSYS);
+ }
+
+ private static void drawPolygon( HSSFPatriarch patriarch )
+ {
+ // HSSFClientAnchor a = new HSSFClientAnchor( 0, 0, 1023, 255, (short) 2, 2, (short) 3, 3 );
+ // HSSFPolygon p = patriarch.createPolygon(a);
+ // p.setPolygonDrawArea(100,100);
+ // p.setPoints( new int[]{30, 90, 50}, new int[]{88, 5, 44} );
+
+
+ HSSFClientAnchor a = new HSSFClientAnchor();
+ a.setAnchor( (short) 2, 2, 0, 0, (short) 3, 3, 1023, 255 );
+ HSSFShapeGroup g = patriarch.createGroup( a );
+ g.setCoordinates(0,0,200,200);
+ HSSFPolygon p1 = g.createPolygon( new HSSFChildAnchor( 0, 0, 200, 200 ) );
+ p1.setPolygonDrawArea( 100, 100 );
+ p1.setPoints( new int[]{0, 90, 50}, new int[]{5, 5, 44} );
+ p1.setFillColor( 0, 255, 0 );
+ HSSFPolygon p2 = g.createPolygon( new HSSFChildAnchor( 20, 20, 200, 200 ) );
+ p2.setPolygonDrawArea( 200, 200 );
+ p2.setPoints( new int[]{120, 20, 150}, new int[]{105, 30, 195} );
+ p2.setFillColor( 255, 0, 0 );
+ }
+
+ private static void drawManyLines( HSSFPatriarch patriarch )
+ {
+ // Draw bunch of lines
+ int x1 = 100;
+ int y1 = 100;
+ int x2 = 800;
+ int y2 = 200;
+ int color = 0;
+ for (int i = 0; i < 10; i++)
+ {
+ HSSFClientAnchor a2 = new HSSFClientAnchor();
+ a2.setAnchor((short) 2, 2, x1, y1, (short) 2, 2, x2, y2);
+ HSSFSimpleShape shape2 = patriarch.createSimpleShape(a2);
+ shape2.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
+ shape2.setLineStyleColor(color);
+ y1 -= 10;
+ y2 -= 10;
+ color += 30;
+ }
+ }
+
+ private static void drawGrid( HSSFPatriarch patriarch )
+ {
+ // This draws a grid of lines. Since the coordinates space fixed at
+ // 1024 by 256 we use a ratio to get a reasonably square grids.
+
+ double xRatio = 3.22;
+ double yRatio = 0.6711;
+
+ int x1 = 0;
+ int y1 = 0;
+ int x2 = 0;
+ int y2 = 200;
+ for (int i = 0; i < 20; i++)
+ {
+ HSSFClientAnchor a2 = new HSSFClientAnchor();
+ a2.setAnchor((short) 2, 2, (int) ( x1 * xRatio ), (int) ( y1 * yRatio ),
+ (short) 2, 2, (int) ( x2 * xRatio ), (int) ( y2 * yRatio ));
+ HSSFSimpleShape shape2 = patriarch.createSimpleShape(a2);
+ shape2.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
+
+ x1 += 10;
+ x2 += 10;
+ }
+
+ x1 = 0;
+ y1 = 0;
+ x2 = 200;
+ y2 = 0;
+ for (int i = 0; i < 20; i++)
+ {
+ HSSFClientAnchor a2 = new HSSFClientAnchor();
+ a2.setAnchor((short) 2, 2, (int) ( x1 * xRatio ), (int) ( y1 * yRatio ),
+ (short) 2, 2, (int) ( x2 * xRatio ), (int) ( y2 * yRatio ));
+ HSSFSimpleShape shape2 = patriarch.createSimpleShape(a2);
+ shape2.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
+
+ y1 += 10;
+ y2 += 10;
+ }
+ }
+
+ private static void drawLinesToCenter( HSSFPatriarch patriarch )
+ {
+ // Draw some lines from and to the corners
+ {
+ HSSFClientAnchor a1 = new HSSFClientAnchor();
+ a1.setAnchor( (short)2, 2, 0, 0, (short) 2, 2, 512, 128);
+ HSSFSimpleShape shape1 = patriarch.createSimpleShape(a1);
+ shape1.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
+ }
+ {
+ HSSFClientAnchor a1 = new HSSFClientAnchor();
+ a1.setAnchor( (short)2, 2, 512, 128, (short) 2, 2, 1024, 0);
+ HSSFSimpleShape shape1 = patriarch.createSimpleShape(a1);
+ shape1.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
+ }
+ {
+ HSSFClientAnchor a1 = new HSSFClientAnchor();
+ a1.setAnchor( (short)1, 1, 0, 0, (short) 1, 1, 512, 100);
+ HSSFSimpleShape shape1 = patriarch.createSimpleShape(a1);
+ shape1.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
+ }
+ {
+ HSSFClientAnchor a1 = new HSSFClientAnchor();
+ a1.setAnchor( (short)1, 1, 512, 100, (short) 1, 1, 1024, 0);
+ HSSFSimpleShape shape1 = patriarch.createSimpleShape(a1);
+ shape1.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
+ }
+
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/OfficeDrawingWithGraphics.java b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/OfficeDrawingWithGraphics.java
new file mode 100644
index 0000000000..eca55d4378
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/OfficeDrawingWithGraphics.java
@@ -0,0 +1,113 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hssf.usermodel;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.RenderingHints;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.EscherGraphics;
+import org.apache.poi.hssf.usermodel.EscherGraphics2d;
+import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
+import org.apache.poi.hssf.usermodel.HSSFPatriarch;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFShapeGroup;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+
+/**
+ * Demonstrates the use of the EscherGraphics2d library.
+ *
+ * @author Glen Stampoultzis (glens at apache.org)
+ */
+public class OfficeDrawingWithGraphics {
+ public static void main( String[] args ) throws IOException {
+ // Create a workbook with one sheet and size the first three somewhat
+ // larger so we can fit the chemical structure diagram in.
+ try (HSSFWorkbook wb = new HSSFWorkbook()) {
+ HSSFSheet sheet = wb.createSheet("my drawing");
+ sheet.setColumnWidth(1, 256 * 27);
+ HSSFRow row1 = sheet.createRow(0);
+ row1.setHeightInPoints(10 * 15f);
+ HSSFRow row2 = sheet.createRow(1);
+ row2.setHeightInPoints(5 * 15f);
+ HSSFRow row3 = sheet.createRow(2);
+ row3.setHeightInPoints(10 * 15f);
+
+ // Add some cells so we can test that the anchoring works when we
+ // sort them.
+ row1.createCell(0).setCellValue("C");
+ row2.createCell(0).setCellValue("A");
+ row3.createCell(0).setCellValue("B");
+
+ // Create the top level drawing patriarch.
+ HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
+
+ HSSFClientAnchor a;
+ HSSFShapeGroup group;
+ EscherGraphics g;
+ EscherGraphics2d g2d;
+ // Anchor entirely within one cell.
+ a = new HSSFClientAnchor(0, 0, 1023, 255, (short) 1, 0, (short) 1, 0);
+ group = patriarch.createGroup(a);
+ group.setCoordinates(0, 0, 320, 276);
+ float verticalPointsPerPixel = a.getAnchorHeightInPoints(sheet) / Math.abs(group.getY2() - group.getY1());
+ g = new EscherGraphics(group, wb, Color.black, verticalPointsPerPixel);
+ g2d = new EscherGraphics2d(g);
+ drawStar(g2d);
+
+ a = new HSSFClientAnchor(0, 0, 1023, 255, (short) 1, 1, (short) 1, 1);
+ group = patriarch.createGroup(a);
+ group.setCoordinates(0, 0, 640, 276);
+ verticalPointsPerPixel = a.getAnchorHeightInPoints(sheet) / Math.abs(group.getY2() - group.getY1());
+// verticalPixelsPerPoint = (float)Math.abs(group.getY2() - group.getY1()) / a.getAnchorHeightInPoints(sheet);
+ g = new EscherGraphics(group, wb, Color.black, verticalPointsPerPixel);
+ g2d = new EscherGraphics2d(g);
+ drawStar(g2d);
+
+ try (FileOutputStream out = new FileOutputStream("workbook.xls")) {
+ wb.write(out);
+ }
+ }
+ }
+
+ private static void drawStar( EscherGraphics2d g2d )
+ {
+ g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
+ for (double i = 0; i < Math.PI; i += 0.1)
+ {
+ g2d.setColor( new Color((int)(i * 5343062d) ) );
+ int x1 = (int) ( Math.cos(i) * 160.0 ) + 160;
+ int y1 = (int) ( Math.sin(i) * 138.0 ) + 138;
+ int x2 = (int) ( -Math.cos(i) * 160.0 ) + 160;
+ int y2 = (int) ( -Math.sin(i) * 138.0 ) + 138;
+ g2d.setStroke(new BasicStroke(2));
+ g2d.drawLine(x1,y1,x2,y2);
+ }
+ g2d.setFont(new Font("SansSerif",Font.BOLD | Font.ITALIC, 20));
+ g2d.drawString("EscherGraphics2d",70,100);
+ g2d.setColor(Color.yellow);
+ g2d.fillOval( 160-20,138-20,40,40);
+ g2d.setColor(Color.black);
+ g2d.fillPolygon(new int[] {-10+160,0+160,10+160,0+160}, new int[] {0+138,10+138,0+138,-10+138}, 4);
+ g2d.drawPolygon(new int[] {-160+160,0+160,160+160,0+160}, new int[] {0+138,138+138,0+138,-138+138}, 4);
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/Outlines.java b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/Outlines.java
new file mode 100644
index 0000000000..42f1b16fc3
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/Outlines.java
@@ -0,0 +1,181 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hssf.usermodel;
+
+import java.io.Closeable;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+
+/**
+ * Creates outlines.
+ */
+public class Outlines implements Closeable {
+ public static void main(String[] args)
+ throws IOException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
+ Logger LOGGER = LogManager.getLogger(Outlines.class);
+ for (int i=1; i<=13; i++) {
+ try (Outlines o = new Outlines()) {
+ String log = (String) Outlines.class.getDeclaredMethod("test" + i).invoke(o);
+ String filename = "outline" + i + ".xls";
+ o.writeOut(filename);
+ LOGGER.atInfo().log("{} written. {}", filename, log);
+ }
+ }
+ }
+
+ private final HSSFWorkbook wb = new HSSFWorkbook();
+ private final HSSFSheet sheet1 = wb.createSheet("new sheet");
+
+ public void writeOut(String filename) throws IOException {
+ try (FileOutputStream fileOut = new FileOutputStream(filename)) {
+ wb.write(fileOut);
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ wb.close();
+ }
+
+ public String test1() {
+ sheet1.groupColumn(4, 7);
+
+ for (int row = 0; row < 200; row++) {
+ HSSFRow r = sheet1.createRow(row);
+ for (int column = 0; column < 200; column++) {
+ HSSFCell c = r.createCell(column);
+ c.setCellValue(column);
+ }
+ }
+ return "Two expanded groups.";
+ }
+
+ public String test2() {
+ sheet1.groupColumn(2, 10);
+ sheet1.groupColumn(4, 7);
+ sheet1.setColumnGroupCollapsed(4, true);
+ return "Two groups. Inner group collapsed.";
+ }
+
+ public String test3() {
+ sheet1.groupColumn(2, 10);
+ sheet1.groupColumn(4, 7);
+ sheet1.setColumnGroupCollapsed(4, true);
+ sheet1.setColumnGroupCollapsed(2, true);
+ return "Two groups. Both collapsed.";
+ }
+
+ public String test4() {
+ sheet1.groupColumn(2, 10);
+ sheet1.groupColumn(4, 7);
+ sheet1.setColumnGroupCollapsed(4, true);
+ sheet1.setColumnGroupCollapsed(2, true);
+
+ sheet1.setColumnGroupCollapsed(4, false);
+ return "Two groups. Collapsed then inner group expanded.";
+ }
+
+ public String test5() {
+ sheet1.groupColumn(2, 10);
+ sheet1.groupColumn(4, 7);
+ sheet1.setColumnGroupCollapsed(4, true);
+ sheet1.setColumnGroupCollapsed(2, true);
+
+ sheet1.setColumnGroupCollapsed(4, false);
+ sheet1.setColumnGroupCollapsed(3, false);
+ return "Two groups. Collapsed then reexpanded.";
+ }
+
+ public String test6() {
+ sheet1.groupColumn(2, 10);
+ sheet1.groupColumn(4, 10);
+ sheet1.setColumnGroupCollapsed(4, true);
+ sheet1.setColumnGroupCollapsed(2, true);
+
+ sheet1.setColumnGroupCollapsed(3, false);
+ return "Two groups with matching end points. Second group collapsed.";
+ }
+
+ public String test7() {
+ sheet1.groupRow(5, 14);
+ sheet1.groupRow(7, 10);
+ return "Row outlines.";
+ }
+
+ public String test8() {
+ sheet1.groupRow(5, 14);
+ sheet1.groupRow(7, 10);
+ sheet1.setRowGroupCollapsed(7, true);
+ return "Row outlines. Inner group collapsed.";
+ }
+
+ public String test9() {
+ sheet1.groupRow(5, 14);
+ sheet1.groupRow(7, 10);
+ sheet1.setRowGroupCollapsed(7, true);
+ sheet1.setRowGroupCollapsed(5, true);
+ return "Row outlines. Both collapsed.";
+ }
+
+ public String test10() {
+ sheet1.groupRow(5, 14);
+ sheet1.groupRow(7, 10);
+ sheet1.setRowGroupCollapsed(7, true);
+ sheet1.setRowGroupCollapsed(5, true);
+ sheet1.setRowGroupCollapsed(8, false);
+ return "Row outlines. Collapsed then inner group expanded.";
+ }
+
+ public String test11() {
+ sheet1.groupRow(5, 14);
+ sheet1.groupRow(7, 10);
+ sheet1.setRowGroupCollapsed(7, true);
+ sheet1.setRowGroupCollapsed(5, true);
+ sheet1.setRowGroupCollapsed(8, false);
+ sheet1.setRowGroupCollapsed(14, false);
+ return "Row outlines. Collapsed then expanded.";
+ }
+
+ public String test12() {
+ sheet1.groupRow(5, 14);
+ sheet1.groupRow(7, 14);
+ sheet1.setRowGroupCollapsed(7, true);
+ sheet1.setRowGroupCollapsed(5, true);
+ sheet1.setRowGroupCollapsed(6, false);
+ return "Row outlines. Two row groups with matching end points. Second group collapsed.";
+ }
+
+ public String test13() {
+ sheet1.groupRow(5, 14);
+ sheet1.groupRow(7, 14);
+ sheet1.groupRow(16, 19);
+
+ sheet1.groupColumn(4, 7);
+ sheet1.groupColumn(9, 12);
+ sheet1.groupColumn(10, 11);
+ return "Mixed bag.";
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/ReadWriteWorkbook.java b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/ReadWriteWorkbook.java
new file mode 100644
index 0000000000..e36b7ad26c
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/ReadWriteWorkbook.java
@@ -0,0 +1,56 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hssf.usermodel;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+
+/**
+ * This example demonstrates opening a workbook, modifying it and writing
+ * the results back out.
+ *
+ * @author Glen Stampoultzis (glens at apache.org)
+ */
+public class ReadWriteWorkbook {
+ public static void main(String[] args) throws IOException {
+ try (FileInputStream fileIn = new FileInputStream("workbook.xls")) {
+ POIFSFileSystem fs = new POIFSFileSystem(fileIn);
+ HSSFWorkbook wb = new HSSFWorkbook(fs);
+ HSSFSheet sheet = wb.getSheetAt(0);
+ HSSFRow row = sheet.getRow(2);
+ if (row == null)
+ row = sheet.createRow(2);
+ HSSFCell cell = row.getCell(3);
+ if (cell == null)
+ cell = row.createCell(3);
+ cell.setCellValue("a test");
+
+ // Write the output to a file
+ try (FileOutputStream fileOut = new FileOutputStream("workbookout.xls")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/RepeatingRowsAndColumns.java b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/RepeatingRowsAndColumns.java
new file mode 100644
index 0000000000..db737cd5bb
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/RepeatingRowsAndColumns.java
@@ -0,0 +1,64 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFCellStyle;
+import org.apache.poi.hssf.usermodel.HSSFFont;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.util.CellRangeAddress;
+
+public class RepeatingRowsAndColumns {
+ public static void main(String[] args) throws IOException {
+ try (HSSFWorkbook wb = new HSSFWorkbook()) {
+ HSSFSheet sheet1 = wb.createSheet("first sheet");
+ HSSFSheet sheet2 = wb.createSheet("second sheet");
+ HSSFSheet sheet3 = wb.createSheet("third sheet");
+
+ HSSFFont boldFont = wb.createFont();
+ boldFont.setFontHeightInPoints((short) 22);
+ boldFont.setBold(true);
+
+ HSSFCellStyle boldStyle = wb.createCellStyle();
+ boldStyle.setFont(boldFont);
+
+ HSSFRow row = sheet1.createRow(1);
+ HSSFCell cell = row.createCell(0);
+ cell.setCellValue("This quick brown fox");
+ cell.setCellStyle(boldStyle);
+
+ // Set the columns to repeat from column 0 to 2 on the first sheet
+ sheet1.setRepeatingColumns(CellRangeAddress.valueOf("A:C"));
+ // Set the rows to repeat from row 0 to 2 on the second sheet.
+ sheet2.setRepeatingRows(CellRangeAddress.valueOf("1:3"));
+ // Set the the repeating rows and columns on the third sheet.
+ CellRangeAddress cra = CellRangeAddress.valueOf("D1:E2");
+ sheet3.setRepeatingColumns(cra);
+ sheet3.setRepeatingRows(cra);
+
+ try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/SplitAndFreezePanes.java b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/SplitAndFreezePanes.java
new file mode 100644
index 0000000000..54c3879e41
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/SplitAndFreezePanes.java
@@ -0,0 +1,51 @@
+
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+
+package org.apache.poi.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.Sheet;
+
+public class SplitAndFreezePanes {
+ public static void main(String[] args) throws IOException {
+ try (HSSFWorkbook wb = new HSSFWorkbook()) {
+ HSSFSheet sheet1 = wb.createSheet("new sheet");
+ HSSFSheet sheet2 = wb.createSheet("second sheet");
+ HSSFSheet sheet3 = wb.createSheet("third sheet");
+ HSSFSheet sheet4 = wb.createSheet("fourth sheet");
+
+ // Freeze just one row
+ sheet1.createFreezePane(0, 1, 0, 1);
+ // Freeze just one column
+ sheet2.createFreezePane(1, 0, 1, 0);
+ // Freeze the columns and rows (forget about scrolling position of the lower right quadrant).
+ sheet3.createFreezePane(2, 2);
+ // Create a split with the lower left side being the active quadrant
+ sheet4.createSplitPane(2000, 2000, 0, 0, Sheet.PANE_LOWER_LEFT);
+
+ try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/WorkingWithFonts.java b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/WorkingWithFonts.java
new file mode 100644
index 0000000000..0c87a335b3
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/WorkingWithFonts.java
@@ -0,0 +1,63 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFCellStyle;
+import org.apache.poi.hssf.usermodel.HSSFFont;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+
+/**
+ * Demonstrates how to create and use fonts.
+ */
+public class WorkingWithFonts {
+ public static void main(String[] args) throws IOException {
+ try (HSSFWorkbook wb = new HSSFWorkbook()) {
+ HSSFSheet sheet = wb.createSheet("new sheet");
+
+ // Create a row and put some cells in it. Rows are 0 based.
+ HSSFRow row = sheet.createRow(1);
+
+ // Create a new font and alter it.
+ HSSFFont font = wb.createFont();
+ font.setFontHeightInPoints((short) 24);
+ font.setFontName("Courier New");
+ font.setItalic(true);
+ font.setStrikeout(true);
+
+ // Fonts are set into a style so create a new one to use.
+ HSSFCellStyle style = wb.createCellStyle();
+ style.setFont(font);
+
+ // Create a cell and put a value in it.
+ HSSFCell cell = row.createCell(1);
+ cell.setCellValue("This is a test of fonts");
+ cell.setCellStyle(style);
+
+ // Write the output to a file
+ try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/ZoomSheet.java b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/ZoomSheet.java
new file mode 100644
index 0000000000..e958489cf7
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hssf/usermodel/ZoomSheet.java
@@ -0,0 +1,45 @@
+
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+
+package org.apache.poi.examples.hssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+
+/**
+ * Sets the zoom magnication for a sheet.
+ *
+ * @author Glen Stampoultzis (glens at apache.org)
+ */
+public class ZoomSheet
+{
+ public static void main(String[] args) throws IOException {
+ try (HSSFWorkbook wb = new HSSFWorkbook()) {
+ HSSFSheet sheet1 = wb.createSheet("new sheet");
+ sheet1.setZoom(75); // 75 percent magnification
+
+ try (FileOutputStream fileOut = new FileOutputStream("workbook.xls")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hwmf/ROP2Table.java b/poi-examples/src/main/java/org/apache/poi/examples/hwmf/ROP2Table.java
new file mode 100644
index 0000000000..a6c0b64978
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hwmf/ROP2Table.java
@@ -0,0 +1,106 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hwmf;
+
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+
+import javax.imageio.ImageIO;
+
+import org.apache.poi.hwmf.draw.HwmfROP2Composite;
+import org.apache.poi.hwmf.record.HwmfBinaryRasterOp;
+import org.apache.poi.util.Units;
+
+/**
+ * Generates an image table describing the various binary raster operations
+ *
+ * inspired from http://www.fengyuan.com/sample/samplech8.html
+ */
+public final class ROP2Table {
+ private static final Color[] COLORS = {
+ new Color(0,0,0),
+ new Color(128,0,0),
+ new Color(0,128,0),
+ new Color(128,128,0),
+ new Color(0,0,128),
+ new Color(128,0,128),
+ new Color(0,128,128),
+ new Color(192,192,192),
+ new Color(255,255,255),
+ new Color(128,128,128),
+ new Color(255,0,0),
+ new Color(0,255,0),
+ new Color(255,255,0),
+ new Color(0,0,255),
+ new Color(255,0,255),
+ new Color(0,255,255)
+ };
+
+ private ROP2Table() {
+ }
+
+ public static void main(String[] args) throws IOException {
+ int square = 800;
+ BufferedImage bi = new BufferedImage(square + 500, square, BufferedImage.TYPE_INT_ARGB);
+ Graphics2D g = bi.createGraphics();
+ double space = 0.2;
+ double hbar = square / (COLORS.length + space);
+ double vbar = square / (COLORS.length + space);
+ double y = hbar * space;
+ double x = vbar * space;
+ double w = square - 2*x;
+ double h = square - 2*y;
+
+ Rectangle2D vrect = new Rectangle2D.Double(x, y, vbar * (1-space), h);
+ for (Color c : COLORS) {
+ g.setColor(c);
+ g.fill(vrect);
+ g.translate(vbar, 0);
+ }
+
+ g.setTransform(new AffineTransform());
+ g.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, (int) Units.pixelToPoints(hbar * 0.8)));
+
+ Composite comp = g.getComposite();
+
+ Rectangle2D hrect = new Rectangle2D.Double(x, y, w, hbar * (1-space));
+ int idx = 0;
+ for (HwmfBinaryRasterOp op : HwmfBinaryRasterOp.values()) {
+ g.setComposite(comp);
+ g.setColor(Color.BLACK);
+ g.drawString(op.name(), (int)(square+vbar), (int)(hbar*0.8));
+ g.setComposite(new HwmfROP2Composite(op));
+ g.setColor(Color.RED);
+ g.fill(hrect);
+ g.translate(0, hbar);
+ idx++;
+ }
+
+ g.dispose();
+ ImageIO.write(bi, "PNG", new File("rop2.png"));
+ }
+
+
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hwmf/ROP3Table.java b/poi-examples/src/main/java/org/apache/poi/examples/hwmf/ROP3Table.java
new file mode 100644
index 0000000000..2e680a0aa3
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hwmf/ROP3Table.java
@@ -0,0 +1,146 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hwmf;
+
+import java.awt.AlphaComposite;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.TexturePaint;
+import java.awt.font.TextLayout;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+
+import javax.imageio.ImageIO;
+
+import org.apache.poi.hwmf.draw.HwmfGraphics;
+import org.apache.poi.hwmf.draw.HwmfROP3Composite;
+import org.apache.poi.hwmf.record.HwmfTernaryRasterOp;
+
+/**
+ * Generates an image table describing the various ternary raster operations
+ *
+ * inspired from http://www.evmsoft.net/en/roptest.html
+ */
+public final class ROP3Table {
+ private ROP3Table() {}
+
+ private static final long PATTERN = 0xAADDAA55AADDAA55L;
+ private static final HwmfTernaryRasterOp[] OPS = HwmfTernaryRasterOp.values();
+ private static final int COLS = 16, BOX = 100;
+ private static final double SCALE = 2, HEADER = 1.1;
+
+ private static final Rectangle2D RECT = new Rectangle2D.Double(0.05*BOX, 0.05*BOX, 0.90*BOX, 0.90*BOX);
+ private static final Shape CIRCLE_BIG = new Ellipse2D.Double(0.15*BOX, 0.15*BOX, 0.70*BOX, 0.70*BOX);
+ private static final Shape CIRCLE_SMALL = new Ellipse2D.Double(0.40*BOX, 0.40*BOX, 0.20*BOX, 0.20*BOX);
+ private static final Shape LABEL_BOX = new Rectangle.Double(0.06*BOX, 0.85*BOX, 0.88*BOX, 0.10*BOX);
+
+ private static final AlphaComposite SRC_OVER = AlphaComposite.getInstance(AlphaComposite.SRC_OVER);
+
+ private static final AffineTransform INIT_AT = AffineTransform.getScaleInstance(SCALE, SCALE);
+
+ public static void main(String[] args) throws IOException {
+ BufferedImage pattern = getPattern();
+ BufferedImage source = getSource();
+
+ BufferedImage dest = new BufferedImage(
+ (int)(BOX * COLS * SCALE),
+ (int)(BOX * (Math.max(OPS.length/COLS,1) + HEADER) * SCALE),
+ BufferedImage.TYPE_INT_ARGB);
+ Graphics2D g = dest.createGraphics();
+ g.setTransform(INIT_AT);
+ g.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 10));
+ g.translate(BOX * (COLS-5) / 2., 0);
+ g.setColor(Color.BLACK);
+
+ fillDest(g);
+ fillLabel(g, "Dest");
+ g.translate(2*BOX, 0);
+ g.drawImage(source, 0, 0, null);
+ fillLabel(g, "Source");
+ g.translate(2*BOX, 0);
+ g.setPaint(new TexturePaint(pattern, RECT));
+ g.fill(RECT);
+ fillLabel(g, "Pattern");
+
+ int idx=0;
+ for (HwmfTernaryRasterOp op : OPS) {
+ g.setTransform(INIT_AT);
+ g.translate(0, HEADER * BOX);
+ g.translate(BOX*(idx%COLS), BOX*(idx/COLS));
+
+ fillDest(g);
+ fillPattern(g, op, pattern, source);
+ fillLabel(g, op.name());
+ idx++;
+ }
+
+ g.dispose();
+ ImageIO.write(dest, "PNG", new File("rop3.png"));
+ }
+
+ private static BufferedImage getPattern() {
+ return HwmfGraphics.getPatternFromLong(PATTERN, Color.BLACK, Color.WHITE, false);
+ }
+
+ private static BufferedImage getSource() {
+ BufferedImage checker = new BufferedImage(BOX, BOX, BufferedImage.TYPE_INT_ARGB);
+ Graphics2D cg = checker.createGraphics();
+ cg.setColor(Color.PINK);
+ cg.fill(RECT);
+ cg.setColor(new Color(0xE6E6FA, false));
+ cg.fill(new Rectangle2D.Double(0.05*BOX, 0.05*BOX, 0.45*BOX, 0.45*BOX));
+ cg.fill(new Rectangle2D.Double(0.50*BOX, 0.50*BOX, 0.45*BOX, 0.45*BOX));
+ cg.dispose();
+ return checker;
+ }
+
+ private static void fillDest(Graphics2D g) {
+ g.setComposite(SRC_OVER);
+ g.setColor(Color.LIGHT_GRAY);
+ g.fill(RECT);
+ g.setColor(new Color(0xDAA520, false));
+ g.fill(CIRCLE_BIG);
+ g.setColor(Color.RED);
+ g.fill(CIRCLE_SMALL);
+ }
+
+ private static void fillPattern(Graphics2D g, HwmfTernaryRasterOp op, BufferedImage pattern, BufferedImage source) {
+ g.setComposite(new HwmfROP3Composite(g.getTransform(), RECT, op, pattern, Color.YELLOW, Color.BLUE));
+ g.setClip(RECT);
+ g.drawImage(source, 0, 0, null);
+ g.setClip(null);
+ g.setComposite(SRC_OVER);
+ }
+
+ private static void fillLabel(Graphics2D g, String str) {
+ g.setColor(Color.WHITE);
+ g.fill(LABEL_BOX);
+ g.setColor(Color.BLACK);
+
+ TextLayout t = new TextLayout(str, g.getFont(), g.getFontRenderContext());
+ Rectangle2D b = t.getBounds();
+ g.drawString(str, (float)((BOX -b.getWidth())/2.), (float)(0.94*BOX));
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/hwpf/Word2Forrest.java b/poi-examples/src/main/java/org/apache/poi/examples/hwpf/Word2Forrest.java
new file mode 100644
index 0000000000..937da16a33
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/hwpf/Word2Forrest.java
@@ -0,0 +1,226 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.hwpf;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.poi.hwpf.HWPFDocument;
+import org.apache.poi.hwpf.model.StyleDescription;
+import org.apache.poi.hwpf.model.StyleSheet;
+import org.apache.poi.hwpf.usermodel.CharacterRun;
+import org.apache.poi.hwpf.usermodel.Paragraph;
+import org.apache.poi.hwpf.usermodel.Range;
+
+@SuppressWarnings({"java:S106","java:S4823"})
+public final class Word2Forrest
+{
+ Writer _out;
+ HWPFDocument _doc;
+
+ @SuppressWarnings("unused")
+ public Word2Forrest(HWPFDocument doc, OutputStream stream) throws IOException
+ {
+ _out = new OutputStreamWriter (stream, StandardCharsets.UTF_8);
+ _doc = doc;
+
+ init ();
+ openDocument ();
+ openBody ();
+
+ Range r = doc.getRange ();
+ StyleSheet styleSheet = doc.getStyleSheet ();
+
+ int sectionLevel = 0;
+ int lenParagraph = r.numParagraphs ();
+ boolean inCode = false;
+ for (int x = 0; x < lenParagraph; x++)
+ {
+ Paragraph p = r.getParagraph (x);
+ String text = p.text ();
+ if (text.trim ().length () == 0)
+ {
+ continue;
+ }
+ StyleDescription paragraphStyle = styleSheet.getStyleDescription (p.
+ getStyleIndex ());
+ String styleName = paragraphStyle.getName();
+ if (styleName.startsWith ("Heading"))
+ {
+ if (inCode)
+ {
+ closeSource();
+ inCode = false;
+ }
+
+ int headerLevel = Integer.parseInt (styleName.substring (8));
+ if (headerLevel > sectionLevel)
+ {
+ openSection ();
+ }
+ else
+ {
+ for (int y = 0; y < (sectionLevel - headerLevel) + 1; y++)
+ {
+ closeSection ();
+ }
+ openSection ();
+ }
+ sectionLevel = headerLevel;
+ openTitle ();
+ writePlainText (text);
+ closeTitle ();
+ }
+ else
+ {
+ int cruns = p.numCharacterRuns ();
+ CharacterRun run = p.getCharacterRun (0);
+ String fontName = run.getFontName();
+ if (fontName.startsWith ("Courier"))
+ {
+ if (!inCode)
+ {
+ openSource ();
+ inCode = true;
+ }
+ writePlainText (p.text());
+ }
+ else
+ {
+ if (inCode)
+ {
+ inCode = false;
+ closeSource();
+ }
+ openParagraph();
+ writePlainText(p.text());
+ closeParagraph();
+ }
+ }
+ }
+ for (int x = 0; x < sectionLevel; x++)
+ {
+ closeSection();
+ }
+ closeBody();
+ closeDocument();
+ _out.flush();
+
+ }
+
+ public void init ()
+ throws IOException
+ {
+ _out.write ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n");
+ _out.write ("<!DOCTYPE document PUBLIC \"-//APACHE//DTD Documentation V1.1//EN\" \"./dtd/document-v11.dtd\">\r\n");
+ }
+
+ public void openDocument ()
+ throws IOException
+ {
+ _out.write ("<document>\r\n");
+ }
+ public void closeDocument ()
+ throws IOException
+ {
+ _out.write ("</document>\r\n");
+ }
+
+
+ public void openBody ()
+ throws IOException
+ {
+ _out.write ("<body>\r\n");
+ }
+
+ public void closeBody ()
+ throws IOException
+ {
+ _out.write ("</body>\r\n");
+ }
+
+
+ public void openSection ()
+ throws IOException
+ {
+ _out.write ("<section>");
+
+ }
+
+ public void closeSection ()
+ throws IOException
+ {
+ _out.write ("</section>");
+
+ }
+
+ public void openTitle ()
+ throws IOException
+ {
+ _out.write ("<title>");
+ }
+
+ public void closeTitle ()
+ throws IOException
+ {
+ _out.write ("</title>");
+ }
+
+ public void writePlainText (String text)
+ throws IOException
+ {
+ _out.write (text);
+ }
+
+ public void openParagraph ()
+ throws IOException
+ {
+ _out.write ("<p>");
+ }
+
+ public void closeParagraph ()
+ throws IOException
+ {
+ _out.write ("</p>");
+ }
+
+ public void openSource ()
+ throws IOException
+ {
+ _out.write ("<source><![CDATA[");
+ }
+ public void closeSource ()
+ throws IOException
+ {
+ _out.write ("]]></source>");
+ }
+
+
+ public static void main(String[] args) throws IOException {
+ try (InputStream is = new FileInputStream(args[0]);
+ OutputStream out = new FileOutputStream("test.xml")) {
+ new Word2Forrest(new HWPFDocument(is), out);
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/ss/AddDimensionedImage.java b/poi-examples/src/main/java/org/apache/poi/examples/ss/AddDimensionedImage.java
new file mode 100644
index 0000000000..6e102038b6
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/ss/AddDimensionedImage.java
@@ -0,0 +1,1011 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+
+package org.apache.poi.examples.ss;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Locale;
+
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.ClientAnchor;
+import org.apache.poi.ss.usermodel.ClientAnchor.AnchorType;
+import org.apache.poi.ss.usermodel.Drawing;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.util.IOUtils;
+
+
+/**
+ * Demonstrates how to add an image to a worksheet and set that images size
+ * to a specific number of millimetres irrespective of the width of the columns
+ * or height of the rows. Overridden methods are provided so that the location
+ * of the image - the cells row and column coordinates that define the top
+ * left hand corners of the image - can be identified either in the familiar
+ * Excel manner - A1 for instance - or using POI's methodology of a column and
+ * row index where 0, 0 would indicate cell A1.
+ *
+ * The best way to make use of these techniques is to delay adding the image to
+ * the sheet until all other work has been completed. That way, the sizes of
+ * all rows and columns will have been adjusted - assuming that step was
+ * necessary. Even though the anchors type is set to prevent the image moving
+ * or re-sizing, this setting does not have any effect until the sheet is being
+ * viewed using the Excel application.
+ *
+ * The key to the process is the ClientAnchor class. It defines methods that allow
+ * us to define the location of an image by specifying the following;
+ *
+ * * How far - in terms of coordinate positions - the image should be inset
+ * from the left hand border of a cell.
+ * * How far - in terms of coordinate positions - the image should be inset
+ * from the from the top of the cell.
+ * * How far - in terms of coordinate positions - the right hand edge of
+ * the image should protrude into a cell (measured from the cells left hand
+ * edge to the images right hand edge).
+ * * How far - in terms of coordinate positions - the bottom edge of the
+ * image should protrude into a row (measured from the cells top edge to
+ * the images bottom edge).
+ * * The index of the column that contains the cell whose top left hand
+ * corner should be aligned with the top left hand corner of the image.
+ * * The index of the row that contains the cell whose top left hand corner
+ * should be aligned with the images top left hand corner.
+ * * The index of the column that contains the cell whose top left hand
+ * corner should be aligned with the images bottom right hand corner
+ * * The index number of the row that contains the cell whose top left
+ * hand corner should be aligned with the images bottom right hand corner.
+ *
+ * It can be used to add an image into cell A1, for example, in the following
+ * manner;
+ *
+ * ClientAnchor anchor = sheet.getWorkbook().getCreationHelper().createClientAnchor();
+ *
+ * anchor.setDx1(0);
+ * anchor.setDy1(0);
+ * anchor.setDx2(0);
+ * anchor.setDy2(0);
+ * anchor.setCol1(0);
+ * anchor.setRow1(0);
+ * anchor.setCol2(1);
+ * anchor.setRow2(1);
+ *
+ * Taken together, the first four methods define the locations of the top left
+ * and bottom right hand corners of the image if you imagine that the image is
+ * represented by a simple rectangle. The setDx1() and setDy1() methods locate
+ * the top left hand corner of the image while setDx2() and and Dy2() locate the
+ * bottom right hand corner of the image. An individual image can be inserted
+ * into a single cell or is can lie across many cells and the latter four methods
+ * are used to define just where the image should be positioned. They do this by
+ * again by identifying where the top left and bottom right hand corners of the
+ * image should be located but this time in terms of the indexes of the cells
+ * in which those corners should be located. The setCol1() and setRow1() methods
+ * together identify the cell that should contain the top left hand corner of
+ * the image while setCol2() and setRow2() do the same for the images bottom
+ * right hand corner.
+ *
+ * Knowing that, it is possible to look again at the example above and to see
+ * that the top left hand corner of the image will be located in cell A1 (0, 0)
+ * and it will be aligned with the very top left hand corner of the cell. Likewise,
+ * the bottom right hand corner of the image will be located in cell B2 (1, 1) and
+ * it will again be aligned with the top left hand corner of the cell. This has the
+ * effect of making the image seem to occupy the whole of cell A1. Interestingly, it
+ * also has an effect on the images resizing behaviour because testing has
+ * demonstrated that if the image is wholly contained within one cell and is not
+ * 'attached' for want of a better word, to a neighbouring cell, then that image
+ * will not increase in size in response to the user dragging the column wider
+ * or the cell higher.
+ *
+ * The following example demonstrates a slightly different way to insert an
+ * image into cell A1 and to ensure that it occupies the whole of the cell. This
+ * is accomplished by specifying the the images bottom right hand corner should be
+ * aligned with the bottom right hand corner of the cell. It is also a case
+ * where the image will not increase in size if the user increases the size of
+ * the enclosing cell - irrespective of the anchors type - but it will reduce in
+ * size if the cell is made smaller.
+ *
+ * ClientAnchor anchor = sheet.getWorkbook().getCreationHelper().createClientAnchor();
+ *
+ * anchor.setDx1(0);
+ * anchor.setDy1(0);
+ * anchor.setDx2(1023);
+ * anchor.setDy2(255);
+ * anchor.setCol1(0);
+ * anchor.setRow1(0);
+ * anchor.setCol2(0);
+ * anchor.setRow2(0);
+ *
+ * Note that the final four method calls all pass the same value and seem to
+ * indicate that the images top left hand corner is aligned with the top left
+ * hand corner of cell A1 and that it's bottom right hand corner is also
+ * aligned with the top left hand corner of cell A1. Yet, running this code
+ * would see the image fully occupying cell A1. That is the result of the
+ * values passed to parameters three and four; these I have referred to as
+ * determining the images coordinates within the cell. They indicate that the
+ * image should occupy - in order - the full width of the column and the full
+ * height of the row.
+ *
+ * The co-ordinate values shown are the maxima; and they are independent of
+ * row height/column width and of the font used. Passing 255 will always result
+ * in the image occupying the full height of the row and passing 1023 will
+ * always result in the image occupying the full width of the column. They help
+ * in situations where an image is larger than a column/row and must overlap
+ * into the next column/row. Using them does mean, however, that it is often
+ * necessary to perform conversions between Excels characters units, points,
+ * pixels and millimetres in order to establish how many rows/columns an image
+ * should occupy and just what the various insets ought to be.
+ *
+ * Note that the setDx1(int) and setDy1(int) methods of the ClientAchor class
+ * are not made use of in the code that follows. It would be fairly trivial
+ * however to extend this example further and provide methods that would centre
+ * an image within a cell or allow the user to specify that a plain border a
+ * fixed number of millimetres wide should wrap around the image. Those first
+ * two parameters would make this sort of functionality perfectly possible.
+ *
+ * Owing to the various conversions used, the actual size of the image may vary
+ * from that required; testing has so far found this to be in the region of
+ * plus or minus two millimetres. Most likely by modifying the way the
+ * calculations are performed - possibly using double(s) throughout and
+ * rounding the values at the correct point - it is likely that these errors
+ * could be reduced or removed.
+ *
+ * A note concerning Excels image resizing behaviour. The ClientAnchor
+ * class contains a method called setAnchorType(int) which can be used to
+ * determine how Excel will resize an image in response to the user increasing
+ * or decreasing the dimensions of the cell containing the image. There are
+ * three values that can be passed to this method; 0 = To move and size the
+ * image with the cell, 2 = To move but don't size the image with the cell,
+ * 3 = To prevent the image from moving or being resized along with the cell. If
+ * an image is inserted using this class and placed into a single cell then if
+ * the setAnchorType(int) method is called and a value of either 0 or 2 passed
+ * to it, the resultant resizing behaviour may be a surprise. The image will not
+ * grow in size of the column is made wider or the row higher but it will shrink
+ * if the columns width or rows height are reduced.
+ *
+ * @author Mark Beardsley [msb at apache.org] and Mark Southern [southern at scripps.edu]
+ * @version 1.00 5th August 2009.
+ * 2.00 26th February 2010.
+ * Ported to make use of the the SS usermodel classes.
+ * Ability to reuse the Drawing Patriarch so that multiple images
+ * can be inserted without unintentionally erasing earlier images.
+ * Check on image type added; i.e. jpg, jpeg or png.
+ * The String used to contain the files name is now converted
+ * into a URL.
+ * 2.10 17th May 2012
+ * Corrected gross error that occurred when using the code with
+ * XSSF or SXSSF workbooks. In short, the code did not correctly
+ * calculate the size of the image(s) owing to the use of EMUs
+ * within the OOXML file format. That problem has largely been
+ * corrected although it should be mentioned that images are not
+ * sized with the same level of accuracy. Discrepancies of up to
+ * 2mm have been noted in testing. Further investigation will
+ * continue to rectify this issue.
+ */
+@SuppressWarnings({"java:S106","java:S4823"})
+public class AddDimensionedImage {
+
+ // Four constants that determine how - and indeed whether - the rows
+ // and columns an image may overlie should be expanded to accommodate that
+ // image.
+ // Passing EXPAND_ROW will result in the height of a row being increased
+ // to accommodate the image if it is not already larger. The image will
+ // be layed across one or more columns.
+ // Passing EXPAND_COLUMN will result in the width of the column being
+ // increased to accommodate the image if it is not already larger. The image
+ // will be layed across one or many rows.
+ // Passing EXPAND_ROW_AND_COLUMN will result in the height of the row
+ // bing increased along with the width of the column to accomdate the
+ // image if either is not already larger.
+ // Passing OVERLAY_ROW_AND_COLUMN will result in the image being layed
+ // over one or more rows and columns. No row or column will be resized,
+ // instead, code will determine how many rows and columns the image should
+ // overlie.
+ public static final int EXPAND_ROW = 1;
+ public static final int EXPAND_COLUMN = 2;
+ public static final int EXPAND_ROW_AND_COLUMN = 3;
+ public static final int OVERLAY_ROW_AND_COLUMN = 7;
+
+ // Modified to support EMU - English Metric Units - used within the OOXML
+ // workbooks, this multoplier is used to convert between measurements in
+ // millimetres and in EMUs
+ private static final int EMU_PER_MM = 36000;
+
+ /**
+ * Add an image to a worksheet.
+ *
+ * @param cellNumber A String that contains the location of the cell whose
+ * top left hand corner should be aligned with the top
+ * left hand corner of the image; for example "A1", "A2"
+ * etc. This is to support the familiar Excel syntax.
+ * Whilst images are are not actually inserted into cells
+ * this provides a convenient method of indicating where
+ * the image should be positioned on the sheet.
+ * @param sheet A reference to the sheet that contains the cell referenced
+ * above.
+ * @param drawing An instance of the DrawingPatriarch class. This is now
+ * passed into the method where it was, previously, recovered
+ * from the sheet in order to allow multiple pictures be
+ * inserted. If the patriarch was not 'cached in this manner
+ * each time it was created any previously positioned images
+ * would be simply over-written.
+ * @param imageFile An instance of the URL class that encapsulates the name
+ * of and path to the image that is to be 'inserted into'
+ * the sheet.
+ * @param reqImageWidthMM A primitive double that contains the required
+ * width of the image in millimetres.
+ * @param reqImageHeightMM A primitive double that contains the required
+ * height of the image in millimetres.
+ * @param resizeBehaviour A primitive int whose value will determine how
+ * the code should react if the image is larger than
+ * the cell referenced by the cellNumber parameter.
+ * Four constants are provided to determine what
+ * should happen;
+ * AddDimensionedImage.EXPAND_ROW
+ * AddDimensionedImage.EXPAND_COLUMN
+ * AddDimensionedImage.EXPAND_ROW_AND_COLUMN
+ * AddDimensionedImage.OVERLAY_ROW_AND_COLUMN
+ * @throws java.io.FileNotFoundException If the file containing the image
+ * cannot be located.
+ * @throws java.io.IOException If a problem occurs whilst reading the file
+ * of image data.
+ * @throws java.lang.IllegalArgumentException If an invalid value is passed
+ * to the resizeBehaviour
+ * parameter.
+ */
+ public void addImageToSheet(String cellNumber, Sheet sheet, Drawing<?> drawing,
+ URL imageFile, double reqImageWidthMM, double reqImageHeightMM,
+ int resizeBehaviour) throws IOException, IllegalArgumentException {
+ // Convert the String into column and row indices then chain the
+ // call to the overridden addImageToSheet() method.
+ CellReference cellRef = new CellReference(cellNumber);
+ this.addImageToSheet(cellRef.getCol(), cellRef.getRow(), sheet, drawing,
+ imageFile, reqImageWidthMM, reqImageHeightMM,resizeBehaviour);
+ }
+
+ /**
+ * Add an image to a worksheet.
+ *
+ * @param colNumber A primitive int that contains the index number of a
+ * column on the worksheet; POI column indices are zero
+ * based. Together with the rowNumber parameter's value,
+ * this parameter identifies a cell on the worksheet. The
+ * images top left hand corner will be aligned with the
+ * top left hand corner of this cell.
+ * @param rowNumber A primitive int that contains the index number of a row
+ * on the worksheet; POI row indices are zero based.
+ * Together with the rowNumber parameter's value, this
+ * parameter identifies a cell on the worksheet. The
+ * images top left hand corner will be aligned with the
+ * top left hand corner of this cell.
+ * @param sheet A reference to the sheet that contains the cell identified
+ * by the two parameters above.
+ * @param drawing An instance of the DrawingPatriarch class. This is now
+ * passed into the method where it was, previously, recovered
+ * from the sheet in order to allow multiple pictures be
+ * inserted. If the patriarch was not 'cached in this manner
+ * each time it was created any previously positioned images
+ * would be simply over-written.
+ * @param imageFile An instance of the URL class that encapsulates the name
+ * of and path to the image that is to be 'inserted into'
+ * the sheet.
+ * @param reqImageWidthMM A primitive double that contains the required
+ * width of the image in millimetres.
+ * @param reqImageHeightMM A primitive double that contains the required
+ * height of the image in millimetres.
+ * @param resizeBehaviour A primitive int whose value will determine how
+ * the code should react if the image is larger than
+ * the cell referenced by the colNumber and
+ * rowNumber parameters. Four constants are provided
+ * to determine what should happen;
+ * AddDimensionedImage.EXPAND_ROW
+ * AddDimensionedImage.EXPAND_COLUMN
+ * AddDimensionedImage.EXPAND_ROW_AND_COLUMN
+ * AddDimensionedImage.OVERLAY_ROW_AND_COLUMN
+ * @throws java.io.FileNotFoundException If the file containing the image
+ * cannot be located.
+ * @throws java.io.IOException If a problem occurs whilst reading the file
+ * of image data.
+ * @throws java.lang.IllegalArgumentException If an invalid value is passed
+ * to the resizeBehaviour
+ * parameter or if the extension
+ * of the image file indicates that
+ * it is of a type that cannot
+ * currently be added to the worksheet.
+ */
+ public void addImageToSheet(int colNumber, int rowNumber, Sheet sheet, Drawing<?> drawing,
+ URL imageFile, double reqImageWidthMM, double reqImageHeightMM,
+ int resizeBehaviour) throws IOException,
+ IllegalArgumentException {
+ ClientAnchor anchor;
+ ClientAnchorDetail rowClientAnchorDetail;
+ ClientAnchorDetail colClientAnchorDetail;
+ int imageType;
+
+ // Validate the resizeBehaviour parameter.
+ if((resizeBehaviour != AddDimensionedImage.EXPAND_COLUMN) &&
+ (resizeBehaviour != AddDimensionedImage.EXPAND_ROW) &&
+ (resizeBehaviour != AddDimensionedImage.EXPAND_ROW_AND_COLUMN) &&
+ (resizeBehaviour != AddDimensionedImage.OVERLAY_ROW_AND_COLUMN)) {
+ throw new IllegalArgumentException("Invalid value passed to the " +
+ "resizeBehaviour parameter of AddDimensionedImage.addImageToSheet()");
+ }
+
+ // Call methods to calculate how the image and sheet should be
+ // manipulated to accommodate the image; columns and then rows.
+ colClientAnchorDetail = this.fitImageToColumns(sheet, colNumber,
+ reqImageWidthMM, resizeBehaviour);
+ rowClientAnchorDetail = this.fitImageToRows(sheet, rowNumber,
+ reqImageHeightMM, resizeBehaviour);
+
+ // Having determined if and how to resize the rows, columns and/or the
+ // image, create the ClientAnchor object to position the image on
+ // the worksheet. Note how the two ClientAnchorDetail records are
+ // interrogated to recover the row/column co-ordinates and any insets.
+ // The first two parameters are not used currently but could be if the
+ // need arose to extend the functionality of this code by adding the
+ // ability to specify that a clear 'border' be placed around the image.
+ anchor = sheet.getWorkbook().getCreationHelper().createClientAnchor();
+
+ anchor.setDx1(0);
+ anchor.setDy1(0);
+ if (colClientAnchorDetail != null) {
+ anchor.setDx2(colClientAnchorDetail.getInset());
+ anchor.setCol1(colClientAnchorDetail.getFromIndex());
+ anchor.setCol2(colClientAnchorDetail.getToIndex());
+ }
+ if (rowClientAnchorDetail != null) {
+ anchor.setDy2(rowClientAnchorDetail.getInset());
+ anchor.setRow1(rowClientAnchorDetail.getFromIndex());
+ anchor.setRow2(rowClientAnchorDetail.getToIndex());
+ }
+
+ // For now, set the anchor type to do not move or resize the
+ // image as the size of the row/column is adjusted. This could easily
+ // become another parameter passed to the method. Please read the note
+ // above regarding the behaviour of image resizing.
+ anchor.setAnchorType(AnchorType.MOVE_AND_RESIZE);
+
+ // Now, add the picture to the workbook. Note that unlike the similar
+ // method in the HSSF Examples section, the image type is checked. First,
+ // the image files location is identified by interrogating the URL passed
+ // to the method, the images type is identified before it is added to the
+ // sheet.
+ String sURL = imageFile.toString().toLowerCase(Locale.ROOT);
+ if( sURL.endsWith(".png") ) {
+ imageType = Workbook.PICTURE_TYPE_PNG;
+ }
+ else if( sURL.endsWith(".jpg") || sURL.endsWith(".jpeg") ) {
+ imageType = Workbook.PICTURE_TYPE_JPEG;
+ }
+ else {
+ throw new IllegalArgumentException("Invalid Image file : " +
+ sURL);
+ }
+ int index = sheet.getWorkbook().addPicture(
+ IOUtils.toByteArray(imageFile.openStream()), imageType);
+ drawing.createPicture(anchor, index);
+ }
+
+ /**
+ * Determines whether the sheets columns should be re-sized to accommodate
+ * the image, adjusts the columns width if necessary and creates then
+ * returns a ClientAnchorDetail object that facilitates construction of
+ * an ClientAnchor that will fix the image on the sheet and establish
+ * it's size.
+ *
+ * @param sheet A reference to the sheet that will 'contain' the image.
+ * @param colNumber A primitive int that contains the index number of a
+ * column on the sheet.
+ * @param reqImageWidthMM A primitive double that contains the required
+ * width of the image in millimetres
+ * @param resizeBehaviour A primitive int whose value will indicate how the
+ * width of the column should be adjusted if the
+ * required width of the image is greater than the
+ * width of the column.
+ * @return An instance of the ClientAnchorDetail class that will contain
+ * the index number of the column containing the cell whose top
+ * left hand corner also defines the top left hand corner of the
+ * image, the index number column containing the cell whose top
+ * left hand corner also defines the bottom right hand corner of
+ * the image and an inset that determines how far the right hand
+ * edge of the image can protrude into the next column - expressed
+ * as a specific number of coordinate positions.
+ */
+ private ClientAnchorDetail fitImageToColumns(Sheet sheet, int colNumber,
+ double reqImageWidthMM, int resizeBehaviour) {
+
+ double colWidthMM;
+ double colCoordinatesPerMM;
+ int pictureWidthCoordinates;
+ ClientAnchorDetail colClientAnchorDetail = null;
+
+ // Get the colum's width in millimetres
+ colWidthMM = ConvertImageUnits.widthUnits2Millimetres(
+ (short)sheet.getColumnWidth(colNumber));
+
+ // Check that the column's width will accommodate the image at the
+ // required dimension. If the width of the column is LESS than the
+ // required width of the image, decide how the application should
+ // respond - resize the column or overlay the image across one or more
+ // columns.
+ if(colWidthMM < reqImageWidthMM) {
+
+ // Should the column's width simply be expanded?
+ if((resizeBehaviour == AddDimensionedImage.EXPAND_COLUMN) ||
+ (resizeBehaviour == AddDimensionedImage.EXPAND_ROW_AND_COLUMN)) {
+ // Set the width of the column by converting the required image
+ // width from millimetres into Excel's column width units.
+ sheet.setColumnWidth(colNumber,
+ ConvertImageUnits.millimetres2WidthUnits(reqImageWidthMM));
+ // To make the image occupy the full width of the column, convert
+ // the required width of the image into co-ordinates. This value
+ // will become the inset for the ClientAnchorDetail class that
+ // is then instantiated.
+ if(sheet instanceof HSSFSheet) {
+ colWidthMM = reqImageWidthMM;
+ colCoordinatesPerMM = colWidthMM == 0 ? 0
+ : ConvertImageUnits.TOTAL_COLUMN_COORDINATE_POSITIONS / colWidthMM;
+ pictureWidthCoordinates = (int)(reqImageWidthMM * colCoordinatesPerMM);
+
+ }
+ else {
+ pictureWidthCoordinates = (int)reqImageWidthMM * AddDimensionedImage.EMU_PER_MM;
+ }
+ colClientAnchorDetail = new ClientAnchorDetail(colNumber,
+ colNumber, pictureWidthCoordinates);
+ }
+ // If the user has chosen to overlay both rows and columns or just
+ // to expand ONLY the size of the rows, then calculate how to lay
+ // the image out across one or more columns.
+ else if ((resizeBehaviour == AddDimensionedImage.OVERLAY_ROW_AND_COLUMN) ||
+ (resizeBehaviour == AddDimensionedImage.EXPAND_ROW)) {
+ colClientAnchorDetail = this.calculateColumnLocation(sheet,
+ colNumber, reqImageWidthMM);
+ }
+ }
+ // If the column is wider than the image.
+ else {
+ if(sheet instanceof HSSFSheet) {
+ // Mow many co-ordinate positions are there per millimetre?
+ colCoordinatesPerMM = ConvertImageUnits.TOTAL_COLUMN_COORDINATE_POSITIONS /
+ colWidthMM;
+ // Given the width of the image, what should be it's co-ordinate?
+ pictureWidthCoordinates = (int)(reqImageWidthMM * colCoordinatesPerMM);
+ }
+ else {
+ pictureWidthCoordinates = (int)reqImageWidthMM *
+ AddDimensionedImage.EMU_PER_MM;
+ }
+ colClientAnchorDetail = new ClientAnchorDetail(colNumber,
+ colNumber, pictureWidthCoordinates);
+ }
+ return(colClientAnchorDetail);
+ }
+
+ /**
+ * Determines whether the sheets row should be re-sized to accommodate
+ * the image, adjusts the rows height if necessary and creates then
+ * returns a ClientAnchorDetail object that facilitates construction of
+ * a ClientAnchor that will fix the image on the sheet and establish
+ * it's size.
+ *
+ * @param sheet A reference to the sheet that will 'contain' the image.
+ * @param rowNumber A primitive int that contains the index number of a
+ * row on the sheet.
+ * @param reqImageHeightMM A primitive double that contains the required
+ * height of the image in millimetres
+ * @param resizeBehaviour A primitive int whose value will indicate how the
+ * height of the row should be adjusted if the
+ * required height of the image is greater than the
+ * height of the row.
+ * @return An instance of the ClientAnchorDetail class that will contain
+ * the index number of the row containing the cell whose top
+ * left hand corner also defines the top left hand corner of the
+ * image, the index number of the row containing the cell whose
+ * top left hand corner also defines the bottom right hand
+ * corner of the image and an inset that determines how far the
+ * bottom edge of the image can protrude into the next (lower)
+ * row - expressed as a specific number of coordinate positions.
+ */
+ private ClientAnchorDetail fitImageToRows(Sheet sheet, int rowNumber,
+ double reqImageHeightMM, int resizeBehaviour) {
+ Row row;
+ double rowHeightMM;
+ double rowCoordinatesPerMM;
+ int pictureHeightCoordinates;
+ ClientAnchorDetail rowClientAnchorDetail = null;
+
+ // Get the row and it's height
+ row = sheet.getRow(rowNumber);
+ if(row == null) {
+ // Create row if it does not exist.
+ row = sheet.createRow(rowNumber);
+ }
+
+ // Get the row's height in millimetres
+ rowHeightMM = row.getHeightInPoints() / ConvertImageUnits.POINTS_PER_MILLIMETRE;
+
+ // Check that the row's height will accommodate the image at the required
+ // dimensions. If the height of the row is LESS than the required height
+ // of the image, decide how the application should respond - resize the
+ // row or overlay the image across a series of rows.
+ if(rowHeightMM < reqImageHeightMM) {
+ if((resizeBehaviour == AddDimensionedImage.EXPAND_ROW) ||
+ (resizeBehaviour == AddDimensionedImage.EXPAND_ROW_AND_COLUMN)) {
+ row.setHeightInPoints((float)(reqImageHeightMM *
+ ConvertImageUnits.POINTS_PER_MILLIMETRE));
+ if(sheet instanceof HSSFSheet) {
+ rowHeightMM = reqImageHeightMM;
+ rowCoordinatesPerMM = rowHeightMM == 0 ? 0
+ : ConvertImageUnits.TOTAL_ROW_COORDINATE_POSITIONS / rowHeightMM;
+ pictureHeightCoordinates = (int)(reqImageHeightMM *
+ rowCoordinatesPerMM);
+ }
+ else {
+ pictureHeightCoordinates = (int)(reqImageHeightMM *
+ AddDimensionedImage.EMU_PER_MM);
+ }
+ rowClientAnchorDetail = new ClientAnchorDetail(rowNumber,
+ rowNumber, pictureHeightCoordinates);
+ }
+ // If the user has chosen to overlay both rows and columns or just
+ // to expand ONLY the size of the columns, then calculate how to lay
+ // the image out ver one or more rows.
+ else if((resizeBehaviour == AddDimensionedImage.OVERLAY_ROW_AND_COLUMN) ||
+ (resizeBehaviour == AddDimensionedImage.EXPAND_COLUMN)) {
+ rowClientAnchorDetail = this.calculateRowLocation(sheet,
+ rowNumber, reqImageHeightMM);
+ }
+ }
+ // Else, if the image is smaller than the space available
+ else {
+ if(sheet instanceof HSSFSheet) {
+ rowCoordinatesPerMM = ConvertImageUnits.TOTAL_ROW_COORDINATE_POSITIONS /
+ rowHeightMM;
+ pictureHeightCoordinates = (int)(reqImageHeightMM * rowCoordinatesPerMM);
+ }
+ else {
+ pictureHeightCoordinates = (int)(reqImageHeightMM *
+ AddDimensionedImage.EMU_PER_MM);
+ }
+ rowClientAnchorDetail = new ClientAnchorDetail(rowNumber,
+ rowNumber, pictureHeightCoordinates);
+ }
+ return(rowClientAnchorDetail);
+ }
+
+ /**
+ * If the image is to overlie more than one column, calculations need to be
+ * performed to determine how many columns and whether the image will
+ * overlie just a part of one column in order to be presented at the
+ * required size.
+ *
+ * @param sheet The sheet that will 'contain' the image.
+ * @param startingColumn A primitive int whose value is the index of the
+ * column that contains the cell whose top left hand
+ * corner should be aligned with the top left hand
+ * corner of the image.
+ * @param reqImageWidthMM A primitive double whose value will indicate the
+ * required width of the image in millimetres.
+ * @return An instance of the ClientAnchorDetail class that will contain
+ * the index number of the column containing the cell whose top
+ * left hand corner also defines the top left hand corner of the
+ * image, the index number column containing the cell whose top
+ * left hand corner also defines the bottom right hand corner of
+ * the image and an inset that determines how far the right hand
+ * edge of the image can protrude into the next column - expressed
+ * as a specific number of coordinate positions.
+ */
+ private ClientAnchorDetail calculateColumnLocation(Sheet sheet,
+ int startingColumn,
+ double reqImageWidthMM) {
+ ClientAnchorDetail anchorDetail;
+ double totalWidthMM = 0.0D;
+ double colWidthMM = 0.0D;
+ double overlapMM;
+ double coordinatePositionsPerMM;
+ int toColumn = startingColumn;
+ int inset;
+
+ // Calculate how many columns the image will have to
+ // span in order to be presented at the required size.
+ while(totalWidthMM < reqImageWidthMM) {
+ colWidthMM = ConvertImageUnits.widthUnits2Millimetres(
+ (short)(sheet.getColumnWidth(toColumn)));
+ // Note use of the cell border width constant. Testing with an image
+ // declared to fit exactly into one column demonstrated that it's
+ // width was greater than the width of the column the POI returned.
+ // Further, this difference was a constant value that I am assuming
+ // related to the cell's borders. Either way, that difference needs
+ // to be allowed for in this calculation.
+ totalWidthMM += (colWidthMM + ConvertImageUnits.CELL_BORDER_WIDTH_MILLIMETRES);
+ toColumn++;
+ }
+ // De-crement by one the last column value.
+ toColumn--;
+ // Highly unlikely that this will be true but, if the width of a series
+ // of columns is exactly equal to the required width of the image, then
+ // simply build a ClientAnchorDetail object with an inset equal to the
+ // total number of co-ordinate positions available in a column, a
+ // from column co-ordinate (top left hand corner) equal to the value
+ // of the startingColumn parameter and a to column co-ordinate equal
+ // to the toColumn variable.
+ //
+ // Convert both values to ints to perform the test.
+ if((int)totalWidthMM == (int)reqImageWidthMM) {
+ // A problem could occur if the image is sized to fit into one or
+ // more columns. If that occurs, the value in the toColumn variable
+ // will be in error. To overcome this, there are two options, to
+ // ibcrement the toColumn variable's value by one or to pass the
+ // total number of co-ordinate positions to the third paramater
+ // of the ClientAnchorDetail constructor. For no sepcific reason,
+ // the latter option is used below.
+ if(sheet instanceof HSSFSheet) {
+ anchorDetail = new ClientAnchorDetail(startingColumn,
+ toColumn, ConvertImageUnits.TOTAL_COLUMN_COORDINATE_POSITIONS);
+ }
+ else {
+ anchorDetail = new ClientAnchorDetail(startingColumn,
+ toColumn, (int)reqImageWidthMM * AddDimensionedImage.EMU_PER_MM);
+ }
+ }
+ // In this case, the image will overlap part of another column and it is
+ // necessary to calculate just how much - this will become the inset
+ // for the ClientAnchorDetail object.
+ else {
+ // Firstly, claculate how much of the image should overlap into
+ // the next column.
+ overlapMM = reqImageWidthMM - (totalWidthMM - colWidthMM);
+
+ // When the required size is very close indded to the column size,
+ // the calcaulation above can produce a negative value. To prevent
+ // problems occuring in later caculations, this is simply removed
+ // be setting the overlapMM value to zero.
+ if(overlapMM < 0) {
+ overlapMM = 0.0D;
+ }
+
+ if(sheet instanceof HSSFSheet) {
+ // Next, from the columns width, calculate how many co-ordinate
+ // positons there are per millimetre
+ coordinatePositionsPerMM = (colWidthMM == 0) ? 0
+ : ConvertImageUnits.TOTAL_COLUMN_COORDINATE_POSITIONS / colWidthMM;
+ // From this figure, determine how many co-ordinat positions to
+ // inset the left hand or bottom edge of the image.
+ inset = (int)(coordinatePositionsPerMM * overlapMM);
+ }
+ else {
+ inset = (int)overlapMM * AddDimensionedImage.EMU_PER_MM;
+ }
+
+ // Now create the ClientAnchorDetail object, setting the from and to
+ // columns and the inset.
+ anchorDetail = new ClientAnchorDetail(startingColumn, toColumn, inset);
+ }
+ return(anchorDetail);
+ }
+
+ /**
+ * If the image is to overlie more than one rows, calculations need to be
+ * performed to determine how many rows and whether the image will
+ * overlie just a part of one row in order to be presented at the
+ * required size.
+ *
+ * @param sheet The sheet that will 'contain' the image.
+ * @param startingRow A primitive int whose value is the index of the row
+ * that contains the cell whose top left hand corner
+ * should be aligned with the top left hand corner of
+ * the image.
+ * @param reqImageHeightMM A primitive double whose value will indicate the
+ * required height of the image in millimetres.
+ * @return An instance of the ClientAnchorDetail class that will contain
+ * the index number of the row containing the cell whose top
+ * left hand corner also defines the top left hand corner of the
+ * image, the index number of the row containing the cell whose top
+ * left hand corner also defines the bottom right hand corner of
+ * the image and an inset that determines how far the bottom edge
+ * can protrude into the next (lower) row - expressed as a specific
+ * number of co-ordinate positions.
+ */
+ private ClientAnchorDetail calculateRowLocation(Sheet sheet,
+ int startingRow, double reqImageHeightMM) {
+ ClientAnchorDetail clientAnchorDetail;
+ Row row;
+ double rowHeightMM = 0.0D;
+ double totalRowHeightMM = 0.0D;
+ double overlapMM;
+ double rowCoordinatesPerMM;
+ int toRow = startingRow;
+ int inset;
+
+ // Step through the rows in the sheet and accumulate a total of their
+ // heights.
+ while(totalRowHeightMM < reqImageHeightMM) {
+ row = sheet.getRow(toRow);
+ // Note, if the row does not already exist on the sheet then create
+ // it here.
+ if(row == null) {
+ row = sheet.createRow(toRow);
+ }
+ // Get the row's height in millimetres and add to the running total.
+ rowHeightMM = row.getHeightInPoints() /
+ ConvertImageUnits.POINTS_PER_MILLIMETRE;
+ totalRowHeightMM += rowHeightMM;
+ toRow++;
+ }
+ // Owing to the way the loop above works, the rowNumber will have been
+ // incremented one row too far. Undo that here.
+ toRow--;
+ // Check to see whether the image should occupy an exact number of
+ // rows. If so, build the ClientAnchorDetail record to point
+ // to those rows and with an inset of the total number of co-ordinate
+ // position in the row.
+ //
+ // To overcome problems that can occur with comparing double values for
+ // equality, cast both to int(s) to truncate the value; VERY crude and
+ // I do not really like it!!
+ if((int)totalRowHeightMM == (int)reqImageHeightMM) {
+ if(sheet instanceof HSSFSheet) {
+ clientAnchorDetail = new ClientAnchorDetail(startingRow, toRow,
+ ConvertImageUnits.TOTAL_ROW_COORDINATE_POSITIONS);
+ }
+ else {
+ clientAnchorDetail = new ClientAnchorDetail(startingRow, toRow,
+ (int)reqImageHeightMM * AddDimensionedImage.EMU_PER_MM);
+ }
+ }
+ else {
+ // Calculate how far the image will project into the next row. Note
+ // that the height of the last row assessed is subtracted from the
+ // total height of all rows assessed so far.
+ overlapMM = reqImageHeightMM - (totalRowHeightMM - rowHeightMM);
+
+ // To prevent an exception being thrown when the required width of
+ // the image is very close indeed to the column size.
+ if(overlapMM < 0) {
+ overlapMM = 0.0D;
+ }
+
+ if(sheet instanceof HSSFSheet) {
+ rowCoordinatesPerMM = (rowHeightMM == 0) ? 0
+ : ConvertImageUnits.TOTAL_ROW_COORDINATE_POSITIONS / rowHeightMM;
+ inset = (int)(overlapMM * rowCoordinatesPerMM);
+ }
+ else {
+ inset = (int)overlapMM * AddDimensionedImage.EMU_PER_MM;
+ }
+ clientAnchorDetail = new ClientAnchorDetail(startingRow,
+ toRow, inset);
+ }
+ return(clientAnchorDetail);
+ }
+
+ /**
+ * The main entry point to the program. It contains code that demonstrates
+ * one way to use the program.
+ *
+ * Note, the code is not restricted to use on new workbooks only. If an
+ * image is to be inserted into an existing workbook. just open that
+ * workbook, gat a reference to a sheet and pass that;
+ *
+ * AddDimensionedImage addImage = new AddDimensionedImage();
+ *
+ * File file = new File("....... Existing Workbook .......");
+ * FileInputStream fis = new FileInputStream(file);
+ * Workbook workbook = new HSSFWorkbook(fis);
+ * HSSFSheet sheet = workbook.getSheetAt(0);
+ * addImage.addImageToSheet("C3", sheet, "image.jpg", 30, 20,
+ * AddDimensionedImage.EXPAND.ROW);
+ *
+ * @param args the command line arguments
+ */
+ public static void main(String[] args) throws IOException {
+ if(args.length < 2){
+ System.err.println("Usage: AddDimensionedImage imageFile outputFile");
+ return;
+ }
+
+ final String imageFile = args[0];
+ final String outputFile = args[1];
+
+ try (final Workbook workbook = new HSSFWorkbook();
+ final FileOutputStream fos = new FileOutputStream(outputFile)) { // OR XSSFWorkbook
+ Sheet sheet = workbook.createSheet("Picture Test");
+ new AddDimensionedImage().addImageToSheet("B5", sheet, sheet.createDrawingPatriarch(),
+ new File(imageFile).toURI().toURL(), 100, 40,
+ AddDimensionedImage.EXPAND_ROW_AND_COLUMN);
+ workbook.write(fos);
+ }
+ }
+
+ /**
+ * The HSSFClientAnchor class accepts eight arguments. In order, these are;
+ *
+ * * How far the left hand edge of the image is inset from the left hand
+ * edge of the cell
+ * * How far the top edge of the image is inset from the top of the cell
+ * * How far the right hand edge of the image is inset from the left
+ * hand edge of the cell
+ * * How far the bottom edge of the image is inset from the top of the
+ * cell.
+ * * Together, arguments five and six determine the column and row
+ * coordinates of the cell whose top left hand corner will be aligned
+ * with the images top left hand corner.
+ * * Together, arguments seven and eight determine the column and row
+ * coordinates of the cell whose top left hand corner will be aligned
+ * with the images bottom right hand corner.
+ *
+ * An instance of the ClientAnchorDetail class provides three of the eight
+ * parameters, one of the coordinates for the images top left hand corner,
+ * one of the coordinates for the images bottom right hand corner and
+ * either how far the image should be inset from the top or the left hand
+ * edge of the cell.
+ *
+ * @author Mark Beardsley [msb at apache.org]
+ * @version 1.00 5th August 2009.
+ */
+ public class ClientAnchorDetail {
+
+ private int fromIndex;
+ private int toIndex;
+ private int inset;
+
+ /**
+ * Create a new instance of the ClientAnchorDetail class using the
+ * following parameters.
+ *
+ * @param fromIndex A primitive int that contains one of the
+ * coordinates (row or column index) for the top left
+ * hand corner of the image.
+ * @param toIndex A primitive int that contains one of the
+ * coordinates (row or column index) for the bottom
+ * right hand corner of the image.
+ * @param inset A primitive int that contains a value which indicates
+ * how far the image should be inset from the top or the
+ * left hand edge of a cell.
+ */
+ public ClientAnchorDetail(int fromIndex, int toIndex, int inset) {
+ this.fromIndex = fromIndex;
+ this.toIndex = toIndex;
+ this.inset = inset;
+ }
+
+ /**
+ * Get one of the number of the column or row that contains the cell
+ * whose top left hand corner will be aligned with the top left hand
+ * corner of the image.
+ *
+ * @return The value - row or column index - for one of the coordinates
+ * of the top left hand corner of the image.
+ */
+ public int getFromIndex() {
+ return(this.fromIndex);
+ }
+
+ /**
+ * Get one of the number of the column or row that contains the cell
+ * whose top left hand corner will be aligned with the bottom right hand
+ * corner of the image.
+ *
+ * @return The value - row or column index - for one of the coordinates
+ * of the bottom right hand corner of the image.
+ */
+ public int getToIndex() {
+ return(this.toIndex);
+ }
+
+ /**
+ * Get the images offset from the edge of a cell.
+ *
+ * @return How far either the right hand or bottom edge of the image is
+ * inset from the left hand or top edge of a cell.
+ */
+ public int getInset() {
+ return(this.inset);
+ }
+ }
+
+ /**
+ * Utility methods used to convert Excels character based column and row
+ * size measurements into pixels and/or millimetres. The class also contains
+ * various constants that are required in other calculations.
+ *
+ * @author xio[darjino@hotmail.com]
+ * @version 1.01 30th July 2009.
+ * Added by Mark Beardsley [msb at apache.org].
+ * Additional constants.
+ * widthUnits2Millimetres() and millimetres2Units() methods.
+ */
+ public static class ConvertImageUnits {
+
+ // Each cell conatins a fixed number of co-ordinate points; this number
+ // does not vary with row height or column width or with font. These two
+ // constants are defined below.
+ public static final int TOTAL_COLUMN_COORDINATE_POSITIONS = 1023;
+ public static final int TOTAL_ROW_COORDINATE_POSITIONS = 255;
+ // The resoultion of an image can be expressed as a specific number
+ // of pixels per inch. Displays and printers differ but 96 pixels per
+ // inch is an acceptable standard to beging with.
+ public static final int PIXELS_PER_INCH = 96;
+ // Cnstants that defines how many pixels and points there are in a
+ // millimetre. These values are required for the conversion algorithm.
+ public static final double PIXELS_PER_MILLIMETRES = 3.78;
+ public static final double POINTS_PER_MILLIMETRE = 2.83;
+ // The column width returned by HSSF and the width of a picture when
+ // positioned to exactly cover one cell are different by almost exactly
+ // 2mm - give or take rounding errors. This constant allows that
+ // additional amount to be accounted for when calculating how many
+ // celles the image ought to overlie.
+ public static final double CELL_BORDER_WIDTH_MILLIMETRES = 2.0D;
+ public static final short EXCEL_COLUMN_WIDTH_FACTOR = 256;
+ public static final int UNIT_OFFSET_LENGTH = 7;
+ private static final int[] UNIT_OFFSET_MAP = { 0, 36, 73, 109, 146, 182, 219 };
+
+ /**
+ * pixel units to excel width units(units of 1/256th of a character width)
+ */
+ public static short pixel2WidthUnits(int pxs) {
+ short widthUnits = (short) (EXCEL_COLUMN_WIDTH_FACTOR *
+ (pxs / UNIT_OFFSET_LENGTH));
+ widthUnits += UNIT_OFFSET_MAP[(pxs % UNIT_OFFSET_LENGTH)];
+ return widthUnits;
+ }
+
+ /**
+ * excel width units(units of 1/256th of a character width) to pixel
+ * units.
+ */
+ public static int widthUnits2Pixel(short widthUnits) {
+ int pixels = (widthUnits / EXCEL_COLUMN_WIDTH_FACTOR)
+ * UNIT_OFFSET_LENGTH;
+ int offsetWidthUnits = widthUnits % EXCEL_COLUMN_WIDTH_FACTOR;
+ pixels += Math.round(offsetWidthUnits /
+ ((float) EXCEL_COLUMN_WIDTH_FACTOR / UNIT_OFFSET_LENGTH));
+ return pixels;
+ }
+
+ /**
+ * Convert Excels width units into millimetres.
+ *
+ * @param widthUnits The width of the column or the height of the
+ * row in Excels units.
+ * @return A primitive double that contains the columns width or rows
+ * height in millimetres.
+ */
+ public static double widthUnits2Millimetres(short widthUnits) {
+ return(ConvertImageUnits.widthUnits2Pixel(widthUnits) /
+ ConvertImageUnits.PIXELS_PER_MILLIMETRES);
+ }
+
+ /**
+ * Convert into millimetres Excels width units..
+ *
+ * @param millimetres A primitive double that contains the columns
+ * width or rows height in millimetres.
+ * @return A primitive int that contains the columns width or rows
+ * height in Excels units.
+ */
+ public static int millimetres2WidthUnits(double millimetres) {
+ return(ConvertImageUnits.pixel2WidthUnits((int)(millimetres *
+ ConvertImageUnits.PIXELS_PER_MILLIMETRES)));
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/ss/AligningCells.java b/poi-examples/src/main/java/org/apache/poi/examples/ss/AligningCells.java
new file mode 100644
index 0000000000..af86efc724
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/ss/AligningCells.java
@@ -0,0 +1,81 @@
+/* ====================================================================
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.ss;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.CreationHelper;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.VerticalAlignment;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Shows how various alignment options work.
+ */
+public class AligningCells {
+
+ public static void main(String[] args) throws IOException {
+ try (Workbook wb = new XSSFWorkbook()) { //or new HSSFWorkbook();
+
+ Sheet sheet = wb.createSheet();
+ Row row = sheet.createRow(2);
+ row.setHeightInPoints(30);
+ for (int i = 0; i < 8; i++) {
+ //column width is set in units of 1/256th of a character width
+ sheet.setColumnWidth(i, 256 * 15);
+ }
+
+ createCell(wb, row, 0, HorizontalAlignment.CENTER, VerticalAlignment.BOTTOM);
+ createCell(wb, row, 1, HorizontalAlignment.CENTER_SELECTION, VerticalAlignment.BOTTOM);
+ createCell(wb, row, 2, HorizontalAlignment.FILL, VerticalAlignment.CENTER);
+ createCell(wb, row, 3, HorizontalAlignment.GENERAL, VerticalAlignment.CENTER);
+ createCell(wb, row, 4, HorizontalAlignment.JUSTIFY, VerticalAlignment.JUSTIFY);
+ createCell(wb, row, 5, HorizontalAlignment.LEFT, VerticalAlignment.TOP);
+ createCell(wb, row, 6, HorizontalAlignment.RIGHT, VerticalAlignment.TOP);
+
+ // Write the output to a file
+ try (OutputStream fileOut = new FileOutputStream("ss-example-align.xlsx")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+
+ /**
+ * Creates a cell and aligns it a certain way.
+ *
+ * @param wb the workbook
+ * @param row the row to create the cell in
+ * @param column the column number to create the cell in
+ * @param halign the horizontal alignment for the cell.
+ */
+ private static void createCell(Workbook wb, Row row, int column, HorizontalAlignment halign, VerticalAlignment valign) {
+ CreationHelper ch = wb.getCreationHelper();
+ Cell cell = row.createCell(column);
+ cell.setCellValue(ch.createRichTextString("Align It"));
+ CellStyle cellStyle = wb.createCellStyle();
+ cellStyle.setAlignment(halign);
+ cellStyle.setVerticalAlignment(valign);
+ cell.setCellStyle(cellStyle);
+ }
+} \ No newline at end of file
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/ss/BusinessPlan.java b/poi-examples/src/main/java/org/apache/poi/examples/ss/BusinessPlan.java
new file mode 100644
index 0000000000..a4865a32a3
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/ss/BusinessPlan.java
@@ -0,0 +1,346 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.ss;
+
+import java.io.FileOutputStream;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.DataFormat;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.usermodel.PrintSetup;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.util.LocaleUtil;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * A business plan demo
+ * Usage:
+ * BusinessPlan -xls|xlsx
+ *
+ * @author Yegor Kozlov
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class BusinessPlan {
+
+ private static final String[] titles = {
+ "ID", "Project Name", "Owner", "Days", "Start", "End"};
+
+ //sample data to fill the sheet.
+ private static final String[][] data = {
+ {"1.0", "Marketing Research Tactical Plan", "J. Dow", "70", "9-Jul", null,
+ "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x"},
+ null,
+ {"1.1", "Scope Definition Phase", "J. Dow", "10", "9-Jul", null,
+ "x", "x", null, null, null, null, null, null, null, null, null},
+ {"1.1.1", "Define research objectives", "J. Dow", "3", "9-Jul", null,
+ "x", null, null, null, null, null, null, null, null, null, null},
+ {"1.1.2", "Define research requirements", "S. Jones", "7", "10-Jul", null,
+ "x", "x", null, null, null, null, null, null, null, null, null},
+ {"1.1.3", "Determine in-house resource or hire vendor", "J. Dow", "2", "15-Jul", null,
+ "x", "x", null, null, null, null, null, null, null, null, null},
+ null,
+ {"1.2", "Vendor Selection Phase", "J. Dow", "19", "19-Jul", null,
+ null, "x", "x", "x", "x", null, null, null, null, null, null},
+ {"1.2.1", "Define vendor selection criteria", "J. Dow", "3", "19-Jul", null,
+ null, "x", null, null, null, null, null, null, null, null, null},
+ {"1.2.2", "Develop vendor selection questionnaire", "S. Jones, T. Wates", "2", "22-Jul", null,
+ null, "x", "x", null, null, null, null, null, null, null, null},
+ {"1.2.3", "Develop Statement of Work", "S. Jones", "4", "26-Jul", null,
+ null, null, "x", "x", null, null, null, null, null, null, null},
+ {"1.2.4", "Evaluate proposal", "J. Dow, S. Jones", "4", "2-Aug", null,
+ null, null, null, "x", "x", null, null, null, null, null, null},
+ {"1.2.5", "Select vendor", "J. Dow", "1", "6-Aug", null,
+ null, null, null, null, "x", null, null, null, null, null, null},
+ null,
+ {"1.3", "Research Phase", "G. Lee", "47", "9-Aug", null,
+ null, null, null, null, "x", "x", "x", "x", "x", "x", "x"},
+ {"1.3.1", "Develop market research information needs questionnaire", "G. Lee", "2", "9-Aug", null,
+ null, null, null, null, "x", null, null, null, null, null, null},
+ {"1.3.2", "Interview marketing group for market research needs", "G. Lee", "2", "11-Aug", null,
+ null, null, null, null, "x", "x", null, null, null, null, null},
+ {"1.3.3", "Document information needs", "G. Lee, S. Jones", "1", "13-Aug", null,
+ null, null, null, null, null, "x", null, null, null, null, null},
+ };
+
+ private BusinessPlan() {}
+
+ public static void main(String[] args) throws Exception {
+ Workbook wb;
+
+ if(args.length > 0 && args[0].equals("-xls")) wb = new HSSFWorkbook();
+ else wb = new XSSFWorkbook();
+
+ final SimpleDateFormat fmt = new SimpleDateFormat("dd-MMM", Locale.ROOT);
+
+ Map<String, CellStyle> styles = createStyles(wb);
+
+ Sheet sheet = wb.createSheet("Business Plan");
+
+ //turn off gridlines
+ sheet.setDisplayGridlines(false);
+ sheet.setPrintGridlines(false);
+ sheet.setFitToPage(true);
+ sheet.setHorizontallyCenter(true);
+ PrintSetup printSetup = sheet.getPrintSetup();
+ printSetup.setLandscape(true);
+
+ //the following three statements are required only for HSSF
+ sheet.setAutobreaks(true);
+ printSetup.setFitHeight((short)1);
+ printSetup.setFitWidth((short)1);
+
+ //the header row: centered text in 48pt font
+ Row headerRow = sheet.createRow(0);
+ headerRow.setHeightInPoints(12.75f);
+ for (int i = 0; i < titles.length; i++) {
+ Cell cell = headerRow.createCell(i);
+ cell.setCellValue(titles[i]);
+ cell.setCellStyle(styles.get("header"));
+ }
+ //columns for 11 weeks starting from 9-Jul
+ Calendar calendar = LocaleUtil.getLocaleCalendar();
+ int year = calendar.get(Calendar.YEAR);
+
+ calendar.setTime(fmt.parse("9-Jul"));
+ calendar.set(Calendar.YEAR, year);
+ for (int i = 0; i < 11; i++) {
+ Cell cell = headerRow.createCell(titles.length + i);
+ cell.setCellValue(calendar);
+ cell.setCellStyle(styles.get("header_date"));
+ calendar.roll(Calendar.WEEK_OF_YEAR, true);
+ }
+ //freeze the first row
+ sheet.createFreezePane(0, 1);
+
+ Row row;
+ Cell cell;
+ int rownum = 1;
+ for (int i = 0; i < data.length; i++, rownum++) {
+ row = sheet.createRow(rownum);
+ if(data[i] == null) continue;
+
+ for (int j = 0; j < data[i].length; j++) {
+ cell = row.createCell(j);
+ String styleName;
+ boolean isHeader = i == 0 || data[i-1] == null;
+ switch(j){
+ case 0:
+ if(isHeader) {
+ styleName = "cell_b";
+ cell.setCellValue(Double.parseDouble(data[i][j]));
+ } else {
+ styleName = "cell_normal";
+ cell.setCellValue(data[i][j]);
+ }
+ break;
+ case 1:
+ if(isHeader) {
+ styleName = i == 0 ? "cell_h" : "cell_bb";
+ } else {
+ styleName = "cell_indented";
+ }
+ cell.setCellValue(data[i][j]);
+ break;
+ case 2:
+ styleName = isHeader ? "cell_b" : "cell_normal";
+ cell.setCellValue(data[i][j]);
+ break;
+ case 3:
+ styleName = isHeader ? "cell_b_centered" : "cell_normal_centered";
+ cell.setCellValue(Integer.parseInt(data[i][j]));
+ break;
+ case 4: {
+ calendar.setTime(fmt.parse(data[i][j]));
+ calendar.set(Calendar.YEAR, year);
+ cell.setCellValue(calendar);
+ styleName = isHeader ? "cell_b_date" : "cell_normal_date";
+ break;
+ }
+ case 5: {
+ int r = rownum + 1;
+ String fmla = "IF(AND(D"+r+",E"+r+"),E"+r+"+D"+r+",\"\")";
+ cell.setCellFormula(fmla);
+ styleName = isHeader ? "cell_bg" : "cell_g";
+ break;
+ }
+ default:
+ styleName = data[i][j] != null ? "cell_blue" : "cell_normal";
+ }
+
+ cell.setCellStyle(styles.get(styleName));
+ }
+ }
+
+ //group rows for each phase, row numbers are 0-based
+ sheet.groupRow(4, 6);
+ sheet.groupRow(9, 13);
+ sheet.groupRow(16, 18);
+
+ //set column widths, the width is measured in units of 1/256th of a character width
+ sheet.setColumnWidth(0, 256*6);
+ sheet.setColumnWidth(1, 256*33);
+ sheet.setColumnWidth(2, 256*20);
+ sheet.setZoom(75); //75% scale
+
+
+ // Write the output to a file
+ String file = "businessplan.xls";
+ if(wb instanceof XSSFWorkbook) file += "x";
+ FileOutputStream out = new FileOutputStream(file);
+ wb.write(out);
+ out.close();
+
+ wb.close();
+ }
+
+ /**
+ * create a library of cell styles
+ */
+ private static Map<String, CellStyle> createStyles(Workbook wb){
+ Map<String, CellStyle> styles = new HashMap<>();
+ DataFormat df = wb.createDataFormat();
+
+ CellStyle style;
+ Font headerFont = wb.createFont();
+ headerFont.setBold(true);
+ style = createBorderedStyle(wb);
+ style.setAlignment(HorizontalAlignment.CENTER);
+ style.setFillForegroundColor(IndexedColors.LIGHT_CORNFLOWER_BLUE.getIndex());
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+ style.setFont(headerFont);
+ styles.put("header", style);
+
+ style = createBorderedStyle(wb);
+ style.setAlignment(HorizontalAlignment.CENTER);
+ style.setFillForegroundColor(IndexedColors.LIGHT_CORNFLOWER_BLUE.getIndex());
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+ style.setFont(headerFont);
+ style.setDataFormat(df.getFormat("d-mmm"));
+ styles.put("header_date", style);
+
+ Font font1 = wb.createFont();
+ font1.setBold(true);
+ style = createBorderedStyle(wb);
+ style.setAlignment(HorizontalAlignment.LEFT);
+ style.setFont(font1);
+ styles.put("cell_b", style);
+
+ style = createBorderedStyle(wb);
+ style.setAlignment(HorizontalAlignment.CENTER);
+ style.setFont(font1);
+ styles.put("cell_b_centered", style);
+
+ style = createBorderedStyle(wb);
+ style.setAlignment(HorizontalAlignment.RIGHT);
+ style.setFont(font1);
+ style.setDataFormat(df.getFormat("d-mmm"));
+ styles.put("cell_b_date", style);
+
+ style = createBorderedStyle(wb);
+ style.setAlignment(HorizontalAlignment.RIGHT);
+ style.setFont(font1);
+ style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+ style.setDataFormat(df.getFormat("d-mmm"));
+ styles.put("cell_g", style);
+
+ Font font2 = wb.createFont();
+ font2.setColor(IndexedColors.BLUE.getIndex());
+ font2.setBold(true);
+ style = createBorderedStyle(wb);
+ style.setAlignment(HorizontalAlignment.LEFT);
+ style.setFont(font2);
+ styles.put("cell_bb", style);
+
+ style = createBorderedStyle(wb);
+ style.setAlignment(HorizontalAlignment.RIGHT);
+ style.setFont(font1);
+ style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+ style.setDataFormat(df.getFormat("d-mmm"));
+ styles.put("cell_bg", style);
+
+ Font font3 = wb.createFont();
+ font3.setFontHeightInPoints((short)14);
+ font3.setColor(IndexedColors.DARK_BLUE.getIndex());
+ font3.setBold(true);
+ style = createBorderedStyle(wb);
+ style.setAlignment(HorizontalAlignment.LEFT);
+ style.setFont(font3);
+ style.setWrapText(true);
+ styles.put("cell_h", style);
+
+ style = createBorderedStyle(wb);
+ style.setAlignment(HorizontalAlignment.LEFT);
+ style.setWrapText(true);
+ styles.put("cell_normal", style);
+
+ style = createBorderedStyle(wb);
+ style.setAlignment(HorizontalAlignment.CENTER);
+ style.setWrapText(true);
+ styles.put("cell_normal_centered", style);
+
+ style = createBorderedStyle(wb);
+ style.setAlignment(HorizontalAlignment.RIGHT);
+ style.setWrapText(true);
+ style.setDataFormat(df.getFormat("d-mmm"));
+ styles.put("cell_normal_date", style);
+
+ style = createBorderedStyle(wb);
+ style.setAlignment(HorizontalAlignment.LEFT);
+ style.setIndention((short)1);
+ style.setWrapText(true);
+ styles.put("cell_indented", style);
+
+ style = createBorderedStyle(wb);
+ style.setFillForegroundColor(IndexedColors.BLUE.getIndex());
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+ styles.put("cell_blue", style);
+
+ return styles;
+ }
+
+ private static CellStyle createBorderedStyle(Workbook wb){
+ BorderStyle thin = BorderStyle.THIN;
+ short black = IndexedColors.BLACK.getIndex();
+
+ CellStyle style = wb.createCellStyle();
+ style.setBorderRight(thin);
+ style.setRightBorderColor(black);
+ style.setBorderBottom(thin);
+ style.setBottomBorderColor(black);
+ style.setBorderLeft(thin);
+ style.setLeftBorderColor(black);
+ style.setBorderTop(thin);
+ style.setTopBorderColor(black);
+ return style;
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/ss/CalendarDemo.java b/poi-examples/src/main/java/org/apache/poi/examples/ss/CalendarDemo.java
new file mode 100644
index 0000000000..ead4093ac4
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/ss/CalendarDemo.java
@@ -0,0 +1,259 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.ss;
+
+import java.io.FileOutputStream;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.usermodel.PrintSetup;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.VerticalAlignment;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.util.LocaleUtil;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * A monthly calendar created using Apache POI. Each month is on a separate sheet.
+ * <pre>
+ * Usage:
+ * CalendarDemo -xls|xlsx &lt;year&gt;
+ * </pre>
+ *
+ * @author Yegor Kozlov
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class CalendarDemo {
+
+ private static final String[] days = {
+ "Sunday", "Monday", "Tuesday",
+ "Wednesday", "Thursday", "Friday", "Saturday"};
+
+ private static final String[] months = {
+ "January", "February", "March","April", "May", "June","July", "August",
+ "September","October", "November", "December"};
+
+ private CalendarDemo() {}
+
+ public static void main(String[] args) throws Exception {
+
+ Calendar calendar = LocaleUtil.getLocaleCalendar();
+ boolean xlsx = true;
+ for (String arg : args) {
+ if (arg.charAt(0) == '-') {
+ xlsx = arg.equals("-xlsx");
+ } else {
+ calendar.set(Calendar.YEAR, Integer.parseInt(arg));
+ }
+ }
+ int year = calendar.get(Calendar.YEAR);
+
+ try (Workbook wb = xlsx ? new XSSFWorkbook() : new HSSFWorkbook()) {
+
+ Map<String, CellStyle> styles = createStyles(wb);
+
+ for (int month = 0; month < 12; month++) {
+ calendar.set(Calendar.MONTH, month);
+ calendar.set(Calendar.DAY_OF_MONTH, 1);
+ //create a sheet for each month
+ Sheet sheet = wb.createSheet(months[month]);
+
+ //turn off gridlines
+ sheet.setDisplayGridlines(false);
+ sheet.setPrintGridlines(false);
+ sheet.setFitToPage(true);
+ sheet.setHorizontallyCenter(true);
+ PrintSetup printSetup = sheet.getPrintSetup();
+ printSetup.setLandscape(true);
+
+ //the following three statements are required only for HSSF
+ sheet.setAutobreaks(true);
+ printSetup.setFitHeight((short) 1);
+ printSetup.setFitWidth((short) 1);
+
+ //the header row: centered text in 48pt font
+ Row headerRow = sheet.createRow(0);
+ headerRow.setHeightInPoints(80);
+ Cell titleCell = headerRow.createCell(0);
+ titleCell.setCellValue(months[month] + " " + year);
+ titleCell.setCellStyle(styles.get("title"));
+ sheet.addMergedRegion(CellRangeAddress.valueOf("$A$1:$N$1"));
+
+ //header with month titles
+ Row monthRow = sheet.createRow(1);
+ for (int i = 0; i < days.length; i++) {
+ //set column widths, the width is measured in units of 1/256th of a character width
+ sheet.setColumnWidth(i * 2, 5 * 256); //the column is 5 characters wide
+ sheet.setColumnWidth(i * 2 + 1, 13 * 256); //the column is 13 characters wide
+ sheet.addMergedRegion(new CellRangeAddress(1, 1, i * 2, i * 2 + 1));
+ Cell monthCell = monthRow.createCell(i * 2);
+ monthCell.setCellValue(days[i]);
+ monthCell.setCellStyle(styles.get("month"));
+ }
+
+ int cnt = 1, day = 1;
+ int rownum = 2;
+ for (int j = 0; j < 6; j++) {
+ Row row = sheet.createRow(rownum++);
+ row.setHeightInPoints(100);
+ for (int i = 0; i < days.length; i++) {
+ Cell dayCell_1 = row.createCell(i * 2);
+ Cell dayCell_2 = row.createCell(i * 2 + 1);
+
+ int day_of_week = calendar.get(Calendar.DAY_OF_WEEK);
+ if (cnt >= day_of_week && calendar.get(Calendar.MONTH) == month) {
+ dayCell_1.setCellValue(day);
+ calendar.set(Calendar.DAY_OF_MONTH, ++day);
+
+ if (i == 0 || i == days.length - 1) {
+ dayCell_1.setCellStyle(styles.get("weekend_left"));
+ dayCell_2.setCellStyle(styles.get("weekend_right"));
+ } else {
+ dayCell_1.setCellStyle(styles.get("workday_left"));
+ dayCell_2.setCellStyle(styles.get("workday_right"));
+ }
+ } else {
+ dayCell_1.setCellStyle(styles.get("grey_left"));
+ dayCell_2.setCellStyle(styles.get("grey_right"));
+ }
+ cnt++;
+ }
+ if (calendar.get(Calendar.MONTH) > month) break;
+ }
+ }
+
+ // Write the output to a file
+ String file = "calendar.xls";
+ if (wb instanceof XSSFWorkbook) file += "x";
+
+ try (FileOutputStream out = new FileOutputStream(file)) {
+ wb.write(out);
+ }
+ }
+ }
+
+ /**
+ * cell styles used for formatting calendar sheets
+ */
+ private static Map<String, CellStyle> createStyles(Workbook wb){
+ Map<String, CellStyle> styles = new HashMap<>();
+
+ short borderColor = IndexedColors.GREY_50_PERCENT.getIndex();
+
+ CellStyle style;
+ Font titleFont = wb.createFont();
+ titleFont.setFontHeightInPoints((short)48);
+ titleFont.setColor(IndexedColors.DARK_BLUE.getIndex());
+ style = wb.createCellStyle();
+ style.setAlignment(HorizontalAlignment.CENTER);
+ style.setVerticalAlignment(VerticalAlignment.CENTER);
+ style.setFont(titleFont);
+ styles.put("title", style);
+
+ Font monthFont = wb.createFont();
+ monthFont.setFontHeightInPoints((short)12);
+ monthFont.setColor(IndexedColors.WHITE.getIndex());
+ monthFont.setBold(true);
+ style = wb.createCellStyle();
+ style.setAlignment(HorizontalAlignment.CENTER);
+ style.setVerticalAlignment(VerticalAlignment.CENTER);
+ style.setFillForegroundColor(IndexedColors.DARK_BLUE.getIndex());
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+ style.setFont(monthFont);
+ styles.put("month", style);
+
+ Font dayFont = wb.createFont();
+ dayFont.setFontHeightInPoints((short)14);
+ dayFont.setBold(true);
+ style = wb.createCellStyle();
+ style.setAlignment(HorizontalAlignment.LEFT);
+ style.setVerticalAlignment(VerticalAlignment.TOP);
+ style.setFillForegroundColor(IndexedColors.LIGHT_CORNFLOWER_BLUE.getIndex());
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+ style.setBorderLeft(BorderStyle.THIN);
+ style.setLeftBorderColor(borderColor);
+ style.setBorderBottom(BorderStyle.THIN);
+ style.setBottomBorderColor(borderColor);
+ style.setFont(dayFont);
+ styles.put("weekend_left", style);
+
+ style = wb.createCellStyle();
+ style.setAlignment(HorizontalAlignment.CENTER);
+ style.setVerticalAlignment(VerticalAlignment.TOP);
+ style.setFillForegroundColor(IndexedColors.LIGHT_CORNFLOWER_BLUE.getIndex());
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+ style.setBorderRight(BorderStyle.THIN);
+ style.setRightBorderColor(borderColor);
+ style.setBorderBottom(BorderStyle.THIN);
+ style.setBottomBorderColor(borderColor);
+ styles.put("weekend_right", style);
+
+ style = wb.createCellStyle();
+ style.setAlignment(HorizontalAlignment.LEFT);
+ style.setVerticalAlignment(VerticalAlignment.TOP);
+ style.setBorderLeft(BorderStyle.THIN);
+ style.setFillForegroundColor(IndexedColors.WHITE.getIndex());
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+ style.setLeftBorderColor(borderColor);
+ style.setBorderBottom(BorderStyle.THIN);
+ style.setBottomBorderColor(borderColor);
+ style.setFont(dayFont);
+ styles.put("workday_left", style);
+
+ style = wb.createCellStyle();
+ style.setAlignment(HorizontalAlignment.CENTER);
+ style.setVerticalAlignment(VerticalAlignment.TOP);
+ style.setFillForegroundColor(IndexedColors.WHITE.getIndex());
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+ style.setBorderRight(BorderStyle.THIN);
+ style.setRightBorderColor(borderColor);
+ style.setBorderBottom(BorderStyle.THIN);
+ style.setBottomBorderColor(borderColor);
+ styles.put("workday_right", style);
+
+ style = wb.createCellStyle();
+ style.setBorderLeft(BorderStyle.THIN);
+ style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+ style.setBorderBottom(BorderStyle.THIN);
+ style.setBottomBorderColor(borderColor);
+ styles.put("grey_left", style);
+
+ style = wb.createCellStyle();
+ style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+ style.setBorderRight(BorderStyle.THIN);
+ style.setRightBorderColor(borderColor);
+ style.setBorderBottom(BorderStyle.THIN);
+ style.setBottomBorderColor(borderColor);
+ styles.put("grey_right", style);
+
+ return styles;
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/ss/CellStyleDetails.java b/poi-examples/src/main/java/org/apache/poi/examples/ss/CellStyleDetails.java
new file mode 100644
index 0000000000..6997a9e8fa
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/ss/CellStyleDetails.java
@@ -0,0 +1,98 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.ss;
+
+import java.io.File;
+
+import org.apache.poi.hssf.usermodel.HSSFFont;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hssf.util.HSSFColor;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.Color;
+import org.apache.poi.ss.usermodel.DataFormatter;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.usermodel.WorkbookFactory;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.xssf.usermodel.XSSFColor;
+import org.apache.poi.xssf.usermodel.XSSFFont;
+
+/**
+ * Demonstrates how to read excel styles for cells
+ */
+@SuppressWarnings({"java:S106","java:S4823"})
+public final class CellStyleDetails {
+ private CellStyleDetails() {}
+
+ public static void main(String[] args) throws Exception {
+ if(args.length == 0) {
+ throw new IllegalArgumentException("Filename must be given");
+ }
+
+ try (Workbook wb = WorkbookFactory.create(new File(args[0]))) {
+ DataFormatter formatter = new DataFormatter();
+
+ for (int sn = 0; sn < wb.getNumberOfSheets(); sn++) {
+ Sheet sheet = wb.getSheetAt(sn);
+ System.out.println("Sheet #" + sn + " : " + sheet.getSheetName());
+
+ for (Row row : sheet) {
+ System.out.println(" Row " + row.getRowNum());
+
+ for (Cell cell : row) {
+ CellReference ref = new CellReference(cell);
+ System.out.print(" " + ref.formatAsString());
+ System.out.print(" (" + cell.getColumnIndex() + ") ");
+
+ CellStyle style = cell.getCellStyle();
+ System.out.print("Format=" + style.getDataFormatString() + " ");
+ System.out.print("FG=" + renderColor(style.getFillForegroundColorColor()) + " ");
+ System.out.print("BG=" + renderColor(style.getFillBackgroundColorColor()) + " ");
+
+ Font font = wb.getFontAt(style.getFontIndex());
+ System.out.print("Font=" + font.getFontName() + " ");
+ System.out.print("FontColor=");
+ if (font instanceof HSSFFont) {
+ System.out.print(renderColor(((HSSFFont) font).getHSSFColor((HSSFWorkbook) wb)));
+ }
+ if (font instanceof XSSFFont) {
+ System.out.print(renderColor(((XSSFFont) font).getXSSFColor()));
+ }
+
+ System.out.println();
+ System.out.println(" " + formatter.formatCellValue(cell));
+ }
+ }
+
+ System.out.println();
+ }
+ }
+ }
+
+ private static String renderColor(Color color) {
+ if(color instanceof HSSFColor) {
+ return ((HSSFColor)color).getHexString();
+ } else if(color instanceof XSSFColor) {
+ return ((XSSFColor)color).getARGBHex();
+ } else {
+ return "(none)";
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/ss/ConditionalFormats.java b/poi-examples/src/main/java/org/apache/poi/examples/ss/ConditionalFormats.java
new file mode 100644
index 0000000000..22eec9633a
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/ss/ConditionalFormats.java
@@ -0,0 +1,732 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.ss;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.formula.ConditionalFormattingEvaluator;
+import org.apache.poi.ss.formula.EvaluationConditionalFormatRule;
+import org.apache.poi.ss.formula.WorkbookEvaluatorProvider;
+import org.apache.poi.ss.usermodel.BuiltinFormats;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.ColorScaleFormatting;
+import org.apache.poi.ss.usermodel.ComparisonOperator;
+import org.apache.poi.ss.usermodel.ConditionalFormattingRule;
+import org.apache.poi.ss.usermodel.ConditionalFormattingThreshold.RangeType;
+import org.apache.poi.ss.usermodel.DataBarFormatting;
+import org.apache.poi.ss.usermodel.ExtendedColor;
+import org.apache.poi.ss.usermodel.FontFormatting;
+import org.apache.poi.ss.usermodel.IconMultiStateFormatting;
+import org.apache.poi.ss.usermodel.IconMultiStateFormatting.IconSet;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.usermodel.PatternFormatting;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.SheetConditionalFormatting;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Excel Conditional Formatting -- Examples
+ *
+ * <p>
+ * Partly based on the code snippets from
+ * http://www.contextures.com/xlcondformat03.html
+ * </p>
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class ConditionalFormats {
+
+ private ConditionalFormats() {}
+
+ /**
+ * generates a sample workbook with conditional formatting,
+ * and prints out a summary of applied formats for one sheet
+ * @param args pass "-xls" to generate an HSSF workbook, default is XSSF
+ */
+ public static void main(String[] args) throws IOException {
+ final boolean isHSSF = args.length > 0 && args[0].equals("-xls");
+ try (Workbook wb = isHSSF ? new HSSFWorkbook() : new XSSFWorkbook()) {
+
+ sameCell(wb.createSheet("Same Cell"));
+ multiCell(wb.createSheet("MultiCell"));
+ overlapping(wb.createSheet("Overlapping"));
+ errors(wb.createSheet("Errors"));
+ hideDupplicates(wb.createSheet("Hide Dups"));
+ formatDuplicates(wb.createSheet("Duplicates"));
+ inList(wb.createSheet("In List"));
+ expiry(wb.createSheet("Expiry"));
+ shadeAlt(wb.createSheet("Shade Alt"));
+ shadeBands(wb.createSheet("Shade Bands"));
+ iconSets(wb.createSheet("Icon Sets"));
+ colourScales(wb.createSheet("Colour Scales"));
+ dataBars(wb.createSheet("Data Bars"));
+
+ // print overlapping rule results
+ evaluateRules(wb, "Overlapping");
+
+ // Write the output to a file
+ String file = "cf-poi.xls";
+ if (wb instanceof XSSFWorkbook) {
+ file += "x";
+ }
+ try (FileOutputStream out = new FileOutputStream(file)) {
+ wb.write(out);
+ }
+ System.out.println("Generated: " + file);
+ }
+ }
+
+ /**
+ * Highlight cells based on their values
+ */
+ static void sameCell(Sheet sheet) {
+ sheet.createRow(0).createCell(0).setCellValue(84);
+ sheet.createRow(1).createCell(0).setCellValue(74);
+ sheet.createRow(2).createCell(0).setCellValue(50);
+ sheet.createRow(3).createCell(0).setCellValue(51);
+ sheet.createRow(4).createCell(0).setCellValue(49);
+ sheet.createRow(5).createCell(0).setCellValue(41);
+
+ SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
+
+ // Condition 1: Cell Value Is greater than 70 (Blue Fill)
+ ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule(ComparisonOperator.GT, "70");
+ PatternFormatting fill1 = rule1.createPatternFormatting();
+ fill1.setFillBackgroundColor(IndexedColors.BLUE.index);
+ fill1.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
+
+ // Condition 2: Cell Value Is less than 50 (Green Fill)
+ ConditionalFormattingRule rule2 = sheetCF.createConditionalFormattingRule(ComparisonOperator.LT, "50");
+ PatternFormatting fill2 = rule2.createPatternFormatting();
+ fill2.setFillBackgroundColor(IndexedColors.GREEN.index);
+ fill2.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
+
+ CellRangeAddress[] regions = {
+ CellRangeAddress.valueOf("A1:A6")
+ };
+
+ sheetCF.addConditionalFormatting(regions, rule1, rule2);
+
+ sheet.getRow(0).createCell(2).setCellValue("<== Condition 1: Cell Value Is greater than 70 (Blue Fill)");
+ sheet.getRow(4).createCell(2).setCellValue("<== Condition 2: Cell Value Is less than 50 (Green Fill)");
+ }
+
+ /**
+ * Highlight multiple cells based on a formula
+ */
+ static void multiCell(Sheet sheet) {
+ // header row
+ Row row0 = sheet.createRow(0);
+ row0.createCell(0).setCellValue("Units");
+ row0.createCell(1).setCellValue("Cost");
+ row0.createCell(2).setCellValue("Total");
+
+ Row row1 = sheet.createRow(1);
+ row1.createCell(0).setCellValue(71);
+ row1.createCell(1).setCellValue(29);
+ row1.createCell(2).setCellValue(2059);
+
+ Row row2 = sheet.createRow(2);
+ row2.createCell(0).setCellValue(85);
+ row2.createCell(1).setCellValue(29);
+ row2.createCell(2).setCellValue(2059);
+
+ Row row3 = sheet.createRow(3);
+ row3.createCell(0).setCellValue(71);
+ row3.createCell(1).setCellValue(29);
+ row3.createCell(2).setCellValue(2059);
+
+ SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
+
+ // Condition 1: Formula Is =$B2>75 (Blue Fill)
+ ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule("$A2>75");
+ PatternFormatting fill1 = rule1.createPatternFormatting();
+ fill1.setFillBackgroundColor(IndexedColors.BLUE.index);
+ fill1.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
+
+ CellRangeAddress[] regions = {
+ CellRangeAddress.valueOf("A2:C4")
+ };
+
+ sheetCF.addConditionalFormatting(regions, rule1);
+
+ sheet.getRow(2).createCell(4).setCellValue("<== Condition 1: Formula Is =$B2>75 (Blue Fill)");
+ }
+
+ /**
+ * Multiple conditional formatting rules can apply to
+ * one cell, some combining, some beating others.
+ * Done in order of the rules added to the
+ * SheetConditionalFormatting object
+ */
+ static void overlapping(Sheet sheet) {
+ for (int i=0; i<40; i++) {
+ int rn = i+1;
+ Row r = sheet.createRow(i);
+ r.createCell(0).setCellValue("This is row " + rn + " (" + i + ")");
+ String str = "";
+ if (rn%2 == 0) {
+ str = str + "even ";
+ }
+ if (rn%3 == 0) {
+ str = str + "x3 ";
+ }
+ if (rn%5 == 0) {
+ str = str + "x5 ";
+ }
+ if (rn%10 == 0) {
+ str = str + "x10 ";
+ }
+ if (str.length() == 0) {
+ str = "nothing special...";
+ }
+ r.createCell(1).setCellValue("It is " + str);
+ }
+ sheet.autoSizeColumn(0);
+ sheet.autoSizeColumn(1);
+
+ sheet.getRow(1).createCell(3).setCellValue("Even rows are blue");
+ sheet.getRow(2).createCell(3).setCellValue("Multiples of 3 have a grey background");
+ sheet.getRow(4).createCell(3).setCellValue("Multiples of 5 are bold");
+ sheet.getRow(9).createCell(3).setCellValue("Multiples of 10 are red (beats even)");
+
+ SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
+
+ // Condition 1: Row divides by 10, red (will beat #1)
+ ConditionalFormattingRule rule1 =
+ sheetCF.createConditionalFormattingRule("MOD(ROW(),10)=0");
+ FontFormatting font1 = rule1.createFontFormatting();
+ font1.setFontColorIndex(IndexedColors.RED.index);
+
+ // Condition 2: Row is even, blue
+ ConditionalFormattingRule rule2 =
+ sheetCF.createConditionalFormattingRule("MOD(ROW(),2)=0");
+ FontFormatting font2 = rule2.createFontFormatting();
+ font2.setFontColorIndex(IndexedColors.BLUE.index);
+
+ // Condition 3: Row divides by 5, bold
+ ConditionalFormattingRule rule3 =
+ sheetCF.createConditionalFormattingRule("MOD(ROW(),5)=0");
+ FontFormatting font3 = rule3.createFontFormatting();
+ font3.setFontStyle(false, true);
+
+ // Condition 4: Row divides by 3, grey background
+ ConditionalFormattingRule rule4 =
+ sheetCF.createConditionalFormattingRule("MOD(ROW(),3)=0");
+ PatternFormatting fill4 = rule4.createPatternFormatting();
+ fill4.setFillBackgroundColor(IndexedColors.GREY_25_PERCENT.index);
+ fill4.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
+
+ // Apply
+ CellRangeAddress[] regions = {
+ CellRangeAddress.valueOf("A1:F41")
+ };
+
+ sheetCF.addConditionalFormatting(regions, rule1);
+ sheetCF.addConditionalFormatting(regions, rule2);
+ sheetCF.addConditionalFormatting(regions, rule3);
+ sheetCF.addConditionalFormatting(regions, rule4);
+ }
+
+ /**
+ * Use Excel conditional formatting to check for errors,
+ * and change the font colour to match the cell colour.
+ * In this example, if formula result is #DIV/0! then it will have white font colour.
+ */
+ static void errors(Sheet sheet) {
+ sheet.createRow(0).createCell(0).setCellValue(84);
+ sheet.createRow(1).createCell(0).setCellValue(0);
+ sheet.createRow(2).createCell(0).setCellFormula("ROUND(A1/A2,0)");
+ sheet.createRow(3).createCell(0).setCellValue(0);
+ sheet.createRow(4).createCell(0).setCellFormula("ROUND(A6/A4,0)");
+ sheet.createRow(5).createCell(0).setCellValue(41);
+
+ SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
+
+ // Condition 1: Formula Is =ISERROR(C2) (White Font)
+ ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule("ISERROR(A1)");
+ FontFormatting font = rule1.createFontFormatting();
+ font.setFontColorIndex(IndexedColors.WHITE.index);
+
+ CellRangeAddress[] regions = {
+ CellRangeAddress.valueOf("A1:A6")
+ };
+
+ sheetCF.addConditionalFormatting(regions, rule1);
+
+ sheet.getRow(2).createCell(1).setCellValue("<== The error in this cell is hidden. Condition: Formula Is =ISERROR(C2) (White Font)");
+ sheet.getRow(4).createCell(1).setCellValue("<== The error in this cell is hidden. Condition: Formula Is =ISERROR(C2) (White Font)");
+ }
+
+ /**
+ * Use Excel conditional formatting to hide the duplicate values,
+ * and make the list easier to read. In this example, when the table is sorted by Region,
+ * the second (and subsequent) occurences of each region name will have white font colour.
+ */
+ static void hideDupplicates(Sheet sheet) {
+ sheet.createRow(0).createCell(0).setCellValue("City");
+ sheet.createRow(1).createCell(0).setCellValue("Boston");
+ sheet.createRow(2).createCell(0).setCellValue("Boston");
+ sheet.createRow(3).createCell(0).setCellValue("Chicago");
+ sheet.createRow(4).createCell(0).setCellValue("Chicago");
+ sheet.createRow(5).createCell(0).setCellValue("New York");
+
+ SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
+
+ // Condition 1: Formula Is =A2=A1 (White Font)
+ ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule("A2=A1");
+ FontFormatting font = rule1.createFontFormatting();
+ font.setFontColorIndex(IndexedColors.WHITE.index);
+
+ CellRangeAddress[] regions = {
+ CellRangeAddress.valueOf("A2:A6")
+ };
+
+ sheetCF.addConditionalFormatting(regions, rule1);
+
+ sheet.getRow(1).createCell(1).setCellValue("<== the second (and subsequent) " +
+ "occurences of each region name will have white font colour. " +
+ "Condition: Formula Is =A2=A1 (White Font)");
+ }
+
+ /**
+ * Use Excel conditional formatting to highlight duplicate entries in a column.
+ */
+ static void formatDuplicates(Sheet sheet) {
+ sheet.createRow(0).createCell(0).setCellValue("Code");
+ sheet.createRow(1).createCell(0).setCellValue(4);
+ sheet.createRow(2).createCell(0).setCellValue(3);
+ sheet.createRow(3).createCell(0).setCellValue(6);
+ sheet.createRow(4).createCell(0).setCellValue(3);
+ sheet.createRow(5).createCell(0).setCellValue(5);
+ sheet.createRow(6).createCell(0).setCellValue(8);
+ sheet.createRow(7).createCell(0).setCellValue(0);
+ sheet.createRow(8).createCell(0).setCellValue(2);
+ sheet.createRow(9).createCell(0).setCellValue(8);
+ sheet.createRow(10).createCell(0).setCellValue(6);
+
+ SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
+
+ // Condition 1: Formula Is =A2=A1 (White Font)
+ ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule("COUNTIF($A$2:$A$11,A2)>1");
+ FontFormatting font = rule1.createFontFormatting();
+ font.setFontStyle(false, true);
+ font.setFontColorIndex(IndexedColors.BLUE.index);
+
+ CellRangeAddress[] regions = {
+ CellRangeAddress.valueOf("A2:A11")
+ };
+
+ sheetCF.addConditionalFormatting(regions, rule1);
+
+ sheet.getRow(2).createCell(1).setCellValue("<== Duplicates numbers in the column are highlighted. " +
+ "Condition: Formula Is =COUNTIF($A$2:$A$11,A2)>1 (Blue Font)");
+ }
+
+ /**
+ * Use Excel conditional formatting to highlight items that are in a list on the worksheet.
+ */
+ static void inList(Sheet sheet) {
+ sheet.createRow(0).createCell(0).setCellValue("Codes");
+ sheet.createRow(1).createCell(0).setCellValue("AA");
+ sheet.createRow(2).createCell(0).setCellValue("BB");
+ sheet.createRow(3).createCell(0).setCellValue("GG");
+ sheet.createRow(4).createCell(0).setCellValue("AA");
+ sheet.createRow(5).createCell(0).setCellValue("FF");
+ sheet.createRow(6).createCell(0).setCellValue("XX");
+ sheet.createRow(7).createCell(0).setCellValue("CC");
+
+ sheet.getRow(0).createCell(2).setCellValue("Valid");
+ sheet.getRow(1).createCell(2).setCellValue("AA");
+ sheet.getRow(2).createCell(2).setCellValue("BB");
+ sheet.getRow(3).createCell(2).setCellValue("CC");
+
+ SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
+
+ // Condition 1: Formula Is =A2=A1 (White Font)
+ ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule("COUNTIF($C$2:$C$4,A2)");
+ PatternFormatting fill1 = rule1.createPatternFormatting();
+ fill1.setFillBackgroundColor(IndexedColors.LIGHT_BLUE.index);
+ fill1.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
+
+ CellRangeAddress[] regions = {
+ CellRangeAddress.valueOf("A2:A8")
+ };
+
+ sheetCF.addConditionalFormatting(regions, rule1);
+
+ sheet.getRow(2).createCell(3).setCellValue("<== Use Excel conditional formatting to highlight items that are in a list on the worksheet");
+ }
+
+ /**
+ * Use Excel conditional formatting to highlight payments that are due in the next thirty days.
+ * In this example, Due dates are entered in cells A2:A4.
+ */
+ static void expiry(Sheet sheet) {
+ CellStyle style = sheet.getWorkbook().createCellStyle();
+ style.setDataFormat((short)BuiltinFormats.getBuiltinFormat("d-mmm"));
+
+ sheet.createRow(0).createCell(0).setCellValue("Date");
+ sheet.createRow(1).createCell(0).setCellFormula("TODAY()+29");
+ sheet.createRow(2).createCell(0).setCellFormula("A2+1");
+ sheet.createRow(3).createCell(0).setCellFormula("A3+1");
+
+ for(int rownum = 1; rownum <= 3; rownum++) {
+ sheet.getRow(rownum).getCell(0).setCellStyle(style);
+ }
+
+ SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
+
+ // Condition 1: Formula Is =A2=A1 (White Font)
+ ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule("AND(A2-TODAY()>=0,A2-TODAY()<=30)");
+ FontFormatting font = rule1.createFontFormatting();
+ font.setFontStyle(false, true);
+ font.setFontColorIndex(IndexedColors.BLUE.index);
+
+ CellRangeAddress[] regions = {
+ CellRangeAddress.valueOf("A2:A4")
+ };
+
+ sheetCF.addConditionalFormatting(regions, rule1);
+
+ sheet.getRow(0).createCell(1).setCellValue("Dates within the next 30 days are highlighted");
+ }
+
+ /**
+ * Use Excel conditional formatting to shade alternating rows on the worksheet
+ */
+ static void shadeAlt(Sheet sheet) {
+ SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
+
+ // Condition 1: Formula Is =A2=A1 (White Font)
+ ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule("MOD(ROW(),2)");
+ PatternFormatting fill1 = rule1.createPatternFormatting();
+ fill1.setFillBackgroundColor(IndexedColors.LIGHT_GREEN.index);
+ fill1.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
+
+ CellRangeAddress[] regions = {
+ CellRangeAddress.valueOf("A1:Z100")
+ };
+
+ sheetCF.addConditionalFormatting(regions, rule1);
+
+ sheet.createRow(0).createCell(1).setCellValue("Shade Alternating Rows");
+ sheet.createRow(1).createCell(1).setCellValue("Condition: Formula Is =MOD(ROW(),2) (Light Green Fill)");
+ }
+
+ /**
+ * You can use Excel conditional formatting to shade bands of rows on the worksheet.
+ * In this example, 3 rows are shaded light grey, and 3 are left with no shading.
+ * In the MOD function, the total number of rows in the set of banded rows (6) is entered.
+ */
+ static void shadeBands(Sheet sheet) {
+ SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
+
+ ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule("MOD(ROW(),6)<3");
+ PatternFormatting fill1 = rule1.createPatternFormatting();
+ fill1.setFillBackgroundColor(IndexedColors.GREY_25_PERCENT.index);
+ fill1.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
+
+ CellRangeAddress[] regions = {
+ CellRangeAddress.valueOf("A1:Z100")
+ };
+
+ sheetCF.addConditionalFormatting(regions, rule1);
+
+ sheet.createRow(0).createCell(1).setCellValue("Shade Bands of Rows");
+ sheet.createRow(1).createCell(1).setCellValue("Condition: Formula Is =MOD(ROW(),6)<2 (Light Grey Fill)");
+ }
+
+ /**
+ * Icon Sets / Multi-States allow you to have icons shown which vary
+ * based on the values, eg Red traffic light / Yellow traffic light /
+ * Green traffic light
+ */
+ static void iconSets(Sheet sheet) {
+ sheet.createRow(0).createCell(0).setCellValue("Icon Sets");
+ Row r = sheet.createRow(1);
+ r.createCell(0).setCellValue("Reds");
+ r.createCell(1).setCellValue(0);
+ r.createCell(2).setCellValue(0);
+ r.createCell(3).setCellValue(0);
+ r = sheet.createRow(2);
+ r.createCell(0).setCellValue("Yellows");
+ r.createCell(1).setCellValue(5);
+ r.createCell(2).setCellValue(5);
+ r.createCell(3).setCellValue(5);
+ r = sheet.createRow(3);
+ r.createCell(0).setCellValue("Greens");
+ r.createCell(1).setCellValue(10);
+ r.createCell(2).setCellValue(10);
+ r.createCell(3).setCellValue(10);
+
+ SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
+
+ CellRangeAddress[] regions = { CellRangeAddress.valueOf("B1:B4") };
+ ConditionalFormattingRule rule1 =
+ sheetCF.createConditionalFormattingRule(IconSet.GYR_3_TRAFFIC_LIGHTS);
+ IconMultiStateFormatting im1 = rule1.getMultiStateFormatting();
+ im1.getThresholds()[0].setRangeType(RangeType.MIN);
+ im1.getThresholds()[1].setRangeType(RangeType.PERCENT);
+ im1.getThresholds()[1].setValue(33d);
+ im1.getThresholds()[2].setRangeType(RangeType.MAX);
+ sheetCF.addConditionalFormatting(regions, rule1);
+
+ regions = new CellRangeAddress[] { CellRangeAddress.valueOf("C1:C4") };
+ ConditionalFormattingRule rule2 =
+ sheetCF.createConditionalFormattingRule(IconSet.GYR_3_FLAGS);
+ IconMultiStateFormatting im2 = rule1.getMultiStateFormatting();
+ im2.getThresholds()[0].setRangeType(RangeType.PERCENT);
+ im2.getThresholds()[0].setValue(0d);
+ im2.getThresholds()[1].setRangeType(RangeType.PERCENT);
+ im2.getThresholds()[1].setValue(33d);
+ im2.getThresholds()[2].setRangeType(RangeType.PERCENT);
+ im2.getThresholds()[2].setValue(67d);
+ sheetCF.addConditionalFormatting(regions, rule2);
+
+ regions = new CellRangeAddress[] { CellRangeAddress.valueOf("D1:D4") };
+ ConditionalFormattingRule rule3 =
+ sheetCF.createConditionalFormattingRule(IconSet.GYR_3_SYMBOLS_CIRCLE);
+ IconMultiStateFormatting im3 = rule1.getMultiStateFormatting();
+ im3.setIconOnly(true);
+ im3.getThresholds()[0].setRangeType(RangeType.MIN);
+ im3.getThresholds()[1].setRangeType(RangeType.NUMBER);
+ im3.getThresholds()[1].setValue(3d);
+ im3.getThresholds()[2].setRangeType(RangeType.NUMBER);
+ im3.getThresholds()[2].setValue(7d);
+ sheetCF.addConditionalFormatting(regions, rule3);
+ }
+
+ /**
+ * Color Scales / Colour Scales / Colour Gradients allow you shade the
+ * background colour of the cell based on the values, eg from Red to
+ * Yellow to Green.
+ */
+ static void colourScales(Sheet sheet) {
+ sheet.createRow(0).createCell(0).setCellValue("Colour Scales");
+ Row r = sheet.createRow(1);
+ r.createCell(0).setCellValue("Red-Yellow-Green");
+ for (int i=1; i<=7; i++) {
+ r.createCell(i).setCellValue((i-1)*5.0);
+ }
+ r = sheet.createRow(2);
+ r.createCell(0).setCellValue("Red-White-Blue");
+ for (int i=1; i<=9; i++) {
+ r.createCell(i).setCellValue((i-1)*5.0);
+ }
+ r = sheet.createRow(3);
+ r.createCell(0).setCellValue("Blue-Green");
+ for (int i=1; i<=16; i++) {
+ r.createCell(i).setCellValue((i-1));
+ }
+ sheet.setColumnWidth(0, 5000);
+
+ SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
+
+ CellRangeAddress[] regions = { CellRangeAddress.valueOf("B2:H2") };
+ ConditionalFormattingRule rule1 =
+ sheetCF.createConditionalFormattingColorScaleRule();
+ ColorScaleFormatting cs1 = rule1.getColorScaleFormatting();
+ cs1.getThresholds()[0].setRangeType(RangeType.MIN);
+ cs1.getThresholds()[1].setRangeType(RangeType.PERCENTILE);
+ cs1.getThresholds()[1].setValue(50d);
+ cs1.getThresholds()[2].setRangeType(RangeType.MAX);
+ ((ExtendedColor)cs1.getColors()[0]).setARGBHex("FFF8696B");
+ ((ExtendedColor)cs1.getColors()[1]).setARGBHex("FFFFEB84");
+ ((ExtendedColor)cs1.getColors()[2]).setARGBHex("FF63BE7B");
+ sheetCF.addConditionalFormatting(regions, rule1);
+
+ regions = new CellRangeAddress[] { CellRangeAddress.valueOf("B3:J3") };
+ ConditionalFormattingRule rule2 =
+ sheetCF.createConditionalFormattingColorScaleRule();
+ ColorScaleFormatting cs2 = rule2.getColorScaleFormatting();
+ cs2.getThresholds()[0].setRangeType(RangeType.MIN);
+ cs2.getThresholds()[1].setRangeType(RangeType.PERCENTILE);
+ cs2.getThresholds()[1].setValue(50d);
+ cs2.getThresholds()[2].setRangeType(RangeType.MAX);
+ ((ExtendedColor)cs2.getColors()[0]).setARGBHex("FFF8696B");
+ ((ExtendedColor)cs2.getColors()[1]).setARGBHex("FFFCFCFF");
+ ((ExtendedColor)cs2.getColors()[2]).setARGBHex("FF5A8AC6");
+ sheetCF.addConditionalFormatting(regions, rule2);
+
+ regions = new CellRangeAddress[] { CellRangeAddress.valueOf("B4:Q4") };
+ ConditionalFormattingRule rule3=
+ sheetCF.createConditionalFormattingColorScaleRule();
+ ColorScaleFormatting cs3 = rule3.getColorScaleFormatting();
+ cs3.setNumControlPoints(2);
+ cs3.getThresholds()[0].setRangeType(RangeType.MIN);
+ cs3.getThresholds()[1].setRangeType(RangeType.MAX);
+ ((ExtendedColor)cs3.getColors()[0]).setARGBHex("FF5A8AC6");
+ ((ExtendedColor)cs3.getColors()[1]).setARGBHex("FF63BE7B");
+ sheetCF.addConditionalFormatting(regions, rule3);
+ }
+
+ /**
+ * DataBars / Data-Bars allow you to have bars shown vary
+ * based on the values, from full to empty
+ */
+ static void dataBars(Sheet sheet) {
+ sheet.createRow(0).createCell(0).setCellValue("Data Bars");
+ Row r = sheet.createRow(1);
+ r.createCell(1).setCellValue("Green Positive");
+ r.createCell(2).setCellValue("Blue Mix");
+ r.createCell(3).setCellValue("Red Negative");
+ r = sheet.createRow(2);
+ r.createCell(1).setCellValue(0);
+ r.createCell(2).setCellValue(0);
+ r.createCell(3).setCellValue(0);
+ r = sheet.createRow(3);
+ r.createCell(1).setCellValue(5);
+ r.createCell(2).setCellValue(-5);
+ r.createCell(3).setCellValue(-5);
+ r = sheet.createRow(4);
+ r.createCell(1).setCellValue(10);
+ r.createCell(2).setCellValue(10);
+ r.createCell(3).setCellValue(-10);
+ r = sheet.createRow(5);
+ r.createCell(1).setCellValue(5);
+ r.createCell(2).setCellValue(5);
+ r.createCell(3).setCellValue(-5);
+ r = sheet.createRow(6);
+ r.createCell(1).setCellValue(20);
+ r.createCell(2).setCellValue(-10);
+ r.createCell(3).setCellValue(-20);
+ sheet.setColumnWidth(0, 3000);
+ sheet.setColumnWidth(1, 5000);
+ sheet.setColumnWidth(2, 5000);
+ sheet.setColumnWidth(3, 5000);
+
+ SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
+
+ ExtendedColor color = sheet.getWorkbook().getCreationHelper().createExtendedColor();
+ color.setARGBHex("FF63BE7B");
+ CellRangeAddress[] regions = { CellRangeAddress.valueOf("B2:B7") };
+ ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule(color);
+ DataBarFormatting db1 = rule1.getDataBarFormatting();
+ db1.getMinThreshold().setRangeType(RangeType.MIN);
+ db1.getMaxThreshold().setRangeType(RangeType.MAX);
+ sheetCF.addConditionalFormatting(regions, rule1);
+
+ color = sheet.getWorkbook().getCreationHelper().createExtendedColor();
+ color.setARGBHex("FF5A8AC6");
+ regions = new CellRangeAddress[] { CellRangeAddress.valueOf("C2:C7") };
+ ConditionalFormattingRule rule2 = sheetCF.createConditionalFormattingRule(color);
+ DataBarFormatting db2 = rule2.getDataBarFormatting();
+ db2.getMinThreshold().setRangeType(RangeType.MIN);
+ db2.getMaxThreshold().setRangeType(RangeType.MAX);
+ sheetCF.addConditionalFormatting(regions, rule2);
+
+ color = sheet.getWorkbook().getCreationHelper().createExtendedColor();
+ color.setARGBHex("FFF8696B");
+ regions = new CellRangeAddress[] { CellRangeAddress.valueOf("D2:D7") };
+ ConditionalFormattingRule rule3 = sheetCF.createConditionalFormattingRule(color);
+ DataBarFormatting db3 = rule3.getDataBarFormatting();
+ db3.getMinThreshold().setRangeType(RangeType.MIN);
+ db3.getMaxThreshold().setRangeType(RangeType.MAX);
+ sheetCF.addConditionalFormatting(regions, rule3);
+ }
+
+ /**
+ * Print out a summary of the conditional formatting rules applied to cells on the given sheet.
+ * Only cells with a matching rule are printed, and for those, all matching rules are sumarized.
+ */
+ static void evaluateRules(Workbook wb, String sheetName) {
+ final WorkbookEvaluatorProvider wbEvalProv = (WorkbookEvaluatorProvider) wb.getCreationHelper().createFormulaEvaluator();
+ final ConditionalFormattingEvaluator cfEval = new ConditionalFormattingEvaluator(wb, wbEvalProv);
+ // if cell values have changed, clear cached format results
+ cfEval.clearAllCachedValues();
+
+ final Sheet sheet = wb.getSheet(sheetName);
+ for (Row r : sheet) {
+ for (Cell c : r) {
+ final List<EvaluationConditionalFormatRule> rules = cfEval.getConditionalFormattingForCell(c);
+ // check rules list for null, although current implementation will return an empty list, not null, then do what you want with results
+ if (rules == null || rules.isEmpty()) {
+ continue;
+ }
+ final CellReference ref = ConditionalFormattingEvaluator.getRef(c);
+ if (rules.isEmpty()) {
+ continue;
+ }
+
+ System.out.println("\n"
+ + ref.formatAsString()
+ + " has conditional formatting.");
+
+ for (EvaluationConditionalFormatRule rule : rules) {
+ ConditionalFormattingRule cf = rule.getRule();
+
+ StringBuilder b = new StringBuilder();
+ b.append("\tRule ")
+ .append(rule.getFormattingIndex())
+ .append(": ");
+
+ // check for color scale
+ if (cf.getColorScaleFormatting() != null) {
+ b.append("\n\t\tcolor scale (caller must calculate bucket)");
+ }
+ // check for data bar
+ if (cf.getDataBarFormatting() != null) {
+ b.append("\n\t\tdata bar (caller must calculate bucket)");
+ }
+ // check for icon set
+ if (cf.getMultiStateFormatting() != null) {
+ b.append("\n\t\ticon set (caller must calculate icon bucket)");
+ }
+ // check for fill
+ if (cf.getPatternFormatting() != null) {
+ final PatternFormatting fill = cf.getPatternFormatting();
+ b.append("\n\t\tfill pattern ")
+ .append(fill.getFillPattern())
+ .append(" color index ")
+ .append(fill.getFillBackgroundColor());
+ }
+ // font stuff
+ if (cf.getFontFormatting() != null) {
+ final FontFormatting ff = cf.getFontFormatting();
+ b.append("\n\t\tfont format ")
+ .append("color index ")
+ .append(ff.getFontColorIndex());
+ if (ff.isBold()) {
+ b.append(" bold");
+ }
+ if (ff.isItalic()) {
+ b.append(" italic");
+ }
+ if (ff.isStruckout()) {
+ b.append(" strikeout");
+ }
+ b.append(" underline index ")
+ .append(ff.getUnderlineType());
+ }
+
+ System.out.println(b);
+ }
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/ss/DrawingBorders.java b/poi-examples/src/main/java/org/apache/poi/examples/ss/DrawingBorders.java
new file mode 100644
index 0000000000..f98d64b2c6
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/ss/DrawingBorders.java
@@ -0,0 +1,107 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.ss;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.BorderExtent;
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.ss.util.PropertyTemplate;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Excel Border Drawing - examples
+ *
+ * <p>
+ * Partly based on the code snippets from
+ * org.apache.poi.ss.examples.ConditionalFormats
+ * </p>
+ */
+@SuppressWarnings({"java:S106","java:S4823"})
+public final class DrawingBorders {
+
+ private DrawingBorders() {}
+
+ public static void main(String[] args) throws IOException {
+ try (Workbook wb = (args.length > 0 && args[0].equals("-xls"))
+ ? new HSSFWorkbook() : new XSSFWorkbook()) {
+ // add a sheet, and put some values into it
+ Sheet sh1 = wb.createSheet("Sheet1");
+ Row r = sh1.createRow(0);
+ Cell c = r.createCell(1);
+ c.setCellValue("All Borders Medium Width");
+ r = sh1.createRow(4);
+ c = r.createCell(1);
+ c.setCellValue("Medium Outside / Thin Inside Borders");
+ r = sh1.createRow(8);
+ c = r.createCell(1);
+ c.setCellValue("Colored Borders");
+
+ // draw borders (three 3x3 grids)
+ PropertyTemplate pt = new PropertyTemplate();
+ // #1) these borders will all be medium in default color
+ pt.drawBorders(new CellRangeAddress(1, 3, 1, 3),
+ BorderStyle.MEDIUM, BorderExtent.ALL);
+ // #2) these cells will have medium outside borders and thin inside borders
+ pt.drawBorders(new CellRangeAddress(5, 7, 1, 3),
+ BorderStyle.MEDIUM, BorderExtent.OUTSIDE);
+ pt.drawBorders(new CellRangeAddress(5, 7, 1, 3), BorderStyle.THIN,
+ BorderExtent.INSIDE);
+ // #3) these cells will all be medium weight with different colors for the
+ // outside, inside horizontal, and inside vertical borders. The center
+ // cell will have no borders.
+ pt.drawBorders(new CellRangeAddress(9, 11, 1, 3),
+ BorderStyle.MEDIUM, IndexedColors.RED.getIndex(),
+ BorderExtent.OUTSIDE);
+ pt.drawBorders(new CellRangeAddress(9, 11, 1, 3),
+ BorderStyle.MEDIUM, IndexedColors.BLUE.getIndex(),
+ BorderExtent.INSIDE_VERTICAL);
+ pt.drawBorders(new CellRangeAddress(9, 11, 1, 3),
+ BorderStyle.MEDIUM, IndexedColors.GREEN.getIndex(),
+ BorderExtent.INSIDE_HORIZONTAL);
+ pt.drawBorders(new CellRangeAddress(10, 10, 2, 2),
+ BorderStyle.NONE,
+ BorderExtent.ALL);
+
+ // apply borders to sheet
+ pt.applyBorders(sh1);
+
+ // add another sheet and apply the borders to it
+ Sheet sh2 = wb.createSheet("Sheet2");
+ pt.applyBorders(sh2);
+
+ // Write the output to a file
+ String file = "db-poi.xls" + (wb instanceof XSSFWorkbook ? "x" : "");
+ try (FileOutputStream out = new FileOutputStream(file)) {
+ wb.write(out);
+ }
+ System.out.println("Generated: " + file);
+ }
+ }
+
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/ss/ExcelComparator.java b/poi-examples/src/main/java/org/apache/poi/examples/ss/ExcelComparator.java
new file mode 100644
index 0000000000..069aef0ebe
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/ss/ExcelComparator.java
@@ -0,0 +1,690 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.ss;
+
+import java.io.File;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Objects;
+
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.ss.usermodel.Color;
+import org.apache.poi.ss.usermodel.DateUtil;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.usermodel.WorkbookFactory;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.xssf.usermodel.XSSFCell;
+import org.apache.poi.xssf.usermodel.XSSFCellStyle;
+import org.apache.poi.xssf.usermodel.XSSFColor;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+
+/**
+ * Utility to compare Excel File Contents cell by cell for all sheets.
+ *
+ * <p>This utility will be used to compare Excel File Contents cell by cell for all sheets programmatically.</p>
+ *
+ * <p>Below are the list of Attribute comparison supported in this version.</p>
+ *
+ * <ul>
+ * <li>Cell Alignment</li>
+ * <li>Cell Border Attributes</li>
+ * <li>Cell Data</li>
+ * <li>Cell Data-Type</li>
+ * <li>Cell Fill Color</li>
+ * <li>Cell Fill pattern</li>
+ * <li>Cell Font Attributes</li>
+ * <li>Cell Font Family</li>
+ * <li>Cell Font Size</li>
+ * <li>Cell Protection</li>
+ * <li>Name of the sheets</li>
+ * <li>Number of Columns</li>
+ * <li>Number of Rows</li>
+ * <li>Number of Sheet</li>
+ * </ul>
+ *
+ * <p>(Some of the above attribute comparison only work for *.xlsx format currently. In future it can be enhanced.)</p>
+ *
+ * <p><b>Usage:</b></p>
+ *
+ * <pre>
+ * {@code
+ * Workbook wb1 = WorkbookFactory.create(new File("workBook1.xls"));
+ * Workbook wb2 = WorkbookFactory.create(new File("workBook2.xls"));
+ * List<String> listOfDifferences = ExcelComparator.compare(wb1, wb2);
+ * for (String differences : listOfDifferences)
+ * System.out.println(differences);
+ * System.out.println("DifferenceFound = "+ excelFileDifference.isDifferenceFound);
+ * }
+ * </pre>
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public class ExcelComparator {
+
+ private static final String CELL_DATA_DOES_NOT_MATCH = "Cell Data does not Match ::";
+ private static final String CELL_FONT_ATTRIBUTES_DOES_NOT_MATCH = "Cell Font Attributes does not Match ::";
+
+ private static class Locator {
+ Workbook workbook;
+ Sheet sheet;
+ Row row;
+ Cell cell;
+ }
+
+ List<String> listOfDifferences = new ArrayList<>();
+ private final DateFormat dateFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.ROOT);
+
+
+ public static void main(String[] args) throws Exception {
+ if (args.length != 2 || !(new File(args[0]).exists()) || !(new File(args[1]).exists())) {
+ System.err.println("java -cp <classpath> "+ExcelComparator.class.getCanonicalName()+" <workbook1.xls/x> <workbook2.xls/x");
+ System.exit(-1);
+ }
+
+ try (Workbook wb1 = WorkbookFactory.create(new File(args[0]), null, true)) {
+ try (Workbook wb2 = WorkbookFactory.create(new File(args[1]), null, true)) {
+ for (String d : ExcelComparator.compare(wb1, wb2)) {
+ System.out.println(d);
+ }
+ }
+ }
+ }
+
+ /**
+ * Utility to compare Excel File Contents cell by cell for all sheets.
+ *
+ * @param wb1 the workbook1
+ * @param wb2 the workbook2
+ * @return the Excel file difference containing a flag and a list of differences
+ */
+ public static List<String> compare(Workbook wb1, Workbook wb2) {
+ Locator loc1 = new Locator();
+ Locator loc2 = new Locator();
+ loc1.workbook = wb1;
+ loc2.workbook = wb2;
+
+ ExcelComparator excelComparator = new ExcelComparator();
+ excelComparator.compareNumberOfSheets(loc1, loc2 );
+ excelComparator.compareSheetNames(loc1, loc2);
+ excelComparator.compareSheetData(loc1, loc2);
+
+ return excelComparator.listOfDifferences;
+ }
+
+ /**
+ * Compare data in all sheets.
+ */
+ private void compareDataInAllSheets(Locator loc1, Locator loc2) {
+ for (int i = 0; i < loc1.workbook.getNumberOfSheets(); i++) {
+ if (loc2.workbook.getNumberOfSheets() <= i) {
+ return;
+ }
+
+ loc1.sheet = loc1.workbook.getSheetAt(i);
+ loc2.sheet = loc2.workbook.getSheetAt(i);
+
+ compareDataInSheet(loc1, loc2);
+ }
+ }
+
+ private void compareDataInSheet(Locator loc1, Locator loc2) {
+ for (int j = 0; j <= loc1.sheet.getLastRowNum(); j++) {
+ if (loc2.sheet.getLastRowNum() <= j) {
+ return;
+ }
+
+ loc1.row = loc1.sheet.getRow(j);
+ loc2.row = loc2.sheet.getRow(j);
+
+ if ((loc1.row == null) || (loc2.row == null)) {
+ continue;
+ }
+
+ compareDataInRow(loc1, loc2);
+ }
+ }
+
+ private void compareDataInRow(Locator loc1, Locator loc2) {
+ for (int k = 0; k <= loc1.row.getLastCellNum(); k++) {
+ if (loc2.row.getLastCellNum() <= k) {
+ return;
+ }
+
+ loc1.cell = loc1.row.getCell(k);
+ loc2.cell = loc2.row.getCell(k);
+
+ if ((loc1.cell == null) || (loc2.cell == null)) {
+ continue;
+ }
+
+ compareDataInCell(loc1, loc2);
+ }
+ }
+
+ private void compareDataInCell(Locator loc1, Locator loc2) {
+ if (isCellTypeMatches(loc1, loc2)) {
+ final CellType loc1cellType = loc1.cell.getCellType();
+ switch(loc1cellType) {
+ case BLANK:
+ case STRING:
+ case ERROR:
+ isCellContentMatches(loc1,loc2);
+ break;
+ case BOOLEAN:
+ isCellContentMatchesForBoolean(loc1,loc2);
+ break;
+ case FORMULA:
+ isCellContentMatchesForFormula(loc1,loc2);
+ break;
+ case NUMERIC:
+ if (DateUtil.isCellDateFormatted(loc1.cell)) {
+ isCellContentMatchesForDate(loc1,loc2);
+ } else {
+ isCellContentMatchesForNumeric(loc1,loc2);
+ }
+ break;
+ default:
+ throw new IllegalStateException("Unexpected cell type: " + loc1cellType);
+ }
+ }
+
+ isCellFillPatternMatches(loc1,loc2);
+ isCellAlignmentMatches(loc1,loc2);
+ isCellHiddenMatches(loc1,loc2);
+ isCellLockedMatches(loc1,loc2);
+ isCellFontFamilyMatches(loc1,loc2);
+ isCellFontSizeMatches(loc1,loc2);
+ isCellFontBoldMatches(loc1,loc2);
+ isCellUnderLineMatches(loc1,loc2);
+ isCellFontItalicsMatches(loc1,loc2);
+ isCellBorderMatches(loc1,loc2,'t');
+ isCellBorderMatches(loc1,loc2,'l');
+ isCellBorderMatches(loc1,loc2,'b');
+ isCellBorderMatches(loc1,loc2,'r');
+ isCellFillBackGroundMatches(loc1,loc2);
+ }
+
+ /**
+ * Compare number of columns in sheets.
+ */
+ private void compareNumberOfColumnsInSheets(Locator loc1, Locator loc2) {
+ for (int i = 0; i < loc1.workbook.getNumberOfSheets(); i++) {
+ if (loc2.workbook.getNumberOfSheets() <= i) {
+ return;
+ }
+
+ loc1.sheet = loc1.workbook.getSheetAt(i);
+ loc2.sheet = loc2.workbook.getSheetAt(i);
+
+ Iterator<Row> ri1 = loc1.sheet.rowIterator();
+ Iterator<Row> ri2 = loc2.sheet.rowIterator();
+
+ int num1 = (ri1.hasNext()) ? ri1.next().getPhysicalNumberOfCells() : 0;
+ int num2 = (ri2.hasNext()) ? ri2.next().getPhysicalNumberOfCells() : 0;
+
+ if (num1 != num2) {
+ String str = String.format(Locale.ROOT, "%s\nworkbook1 -> %s [%d] != workbook2 -> %s [%d]",
+ "Number Of Columns does not Match ::",
+ loc1.sheet.getSheetName(), num1,
+ loc2.sheet.getSheetName(), num2
+ );
+ listOfDifferences.add(str);
+ }
+ }
+ }
+
+ /**
+ * Compare number of rows in sheets.
+ */
+ private void compareNumberOfRowsInSheets(Locator loc1, Locator loc2) {
+ for (int i = 0; i < loc1.workbook.getNumberOfSheets(); i++) {
+ if (loc2.workbook.getNumberOfSheets() <= i) {
+ return;
+ }
+
+ loc1.sheet = loc1.workbook.getSheetAt(i);
+ loc2.sheet = loc2.workbook.getSheetAt(i);
+
+ int num1 = loc1.sheet.getPhysicalNumberOfRows();
+ int num2 = loc2.sheet.getPhysicalNumberOfRows();
+
+ if (num1 != num2) {
+ String str = String.format(Locale.ROOT, "%s\nworkbook1 -> %s [%d] != workbook2 -> %s [%d]",
+ "Number Of Rows does not Match ::",
+ loc1.sheet.getSheetName(), num1,
+ loc2.sheet.getSheetName(), num2
+ );
+ listOfDifferences.add(str);
+ }
+ }
+
+ }
+
+ /**
+ * Compare number of sheets.
+ */
+ private void compareNumberOfSheets(Locator loc1, Locator loc2) {
+ int num1 = loc1.workbook.getNumberOfSheets();
+ int num2 = loc2.workbook.getNumberOfSheets();
+ if (num1 != num2) {
+ String str = String.format(Locale.ROOT, "%s\nworkbook1 [%d] != workbook2 [%d]",
+ "Number of Sheets do not match ::",
+ num1, num2
+ );
+
+ listOfDifferences.add(str);
+
+ }
+ }
+
+ /**
+ * Compare sheet data.
+ */
+ private void compareSheetData(Locator loc1, Locator loc2) {
+ compareNumberOfRowsInSheets(loc1, loc2);
+ compareNumberOfColumnsInSheets(loc1, loc2);
+ compareDataInAllSheets(loc1, loc2);
+
+ }
+
+ /**
+ * Compare sheet names.
+ */
+ private void compareSheetNames(Locator loc1, Locator loc2) {
+ for (int i = 0; i < loc1.workbook.getNumberOfSheets(); i++) {
+ String name1 = loc1.workbook.getSheetName(i);
+ String name2 = (loc2.workbook.getNumberOfSheets() > i) ? loc2.workbook.getSheetName(i) : "";
+
+ if (!name1.equals(name2)) {
+ String str = String.format(Locale.ROOT, "%s\nworkbook1 -> %s [%d] != workbook2 -> %s [%d]",
+ "Name of the sheets do not match ::", name1, i+1, name2, i+1
+ );
+ listOfDifferences.add(str);
+ }
+ }
+ }
+
+ /**
+ * Formats the message.
+ */
+ private void addMessage(Locator loc1, Locator loc2, String messageStart, String value1, String value2) {
+ String str =
+ String.format(Locale.ROOT, "%s\nworkbook1 -> %s -> %s [%s] != workbook2 -> %s -> %s [%s]",
+ messageStart,
+ loc1.sheet.getSheetName(), new CellReference(loc1.cell).formatAsString(), value1,
+ loc2.sheet.getSheetName(), new CellReference(loc2.cell).formatAsString(), value2
+ );
+ listOfDifferences.add(str);
+ }
+
+ /**
+ * Checks if cell alignment matches.
+ */
+ private void isCellAlignmentMatches(Locator loc1, Locator loc2) {
+ if(loc1.cell.getCellStyle() == null || loc2.cell.getCellStyle() == null) {
+ return;
+ }
+
+ HorizontalAlignment align1 = loc1.cell.getCellStyle().getAlignment();
+ HorizontalAlignment align2 = loc2.cell.getCellStyle().getAlignment();
+ if (align1 != align2) {
+ addMessage(loc1, loc2,
+ "Cell Alignment does not Match ::",
+ align1.name(),
+ align2.name()
+ );
+ }
+ }
+
+ /**
+ * Checks if cell border bottom matches.
+ */
+ private void isCellBorderMatches(Locator loc1, Locator loc2, char borderSide) {
+ if (!(loc1.cell instanceof XSSFCell) ||
+ loc1.cell.getCellStyle() == null || loc2.cell.getCellStyle() == null) {
+ return;
+ }
+
+ XSSFCellStyle style1 = ((XSSFCell)loc1.cell).getCellStyle();
+ XSSFCellStyle style2 = ((XSSFCell)loc2.cell).getCellStyle();
+ boolean b1, b2;
+ String borderName;
+ switch (borderSide) {
+ case 't': default:
+ b1 = style1.getBorderTop() == BorderStyle.THIN;
+ b2 = style2.getBorderTop() == BorderStyle.THIN;
+ borderName = "TOP";
+ break;
+ case 'b':
+ b1 = style1.getBorderBottom() == BorderStyle.THIN;
+ b2 = style2.getBorderBottom() == BorderStyle.THIN;
+ borderName = "BOTTOM";
+ break;
+ case 'l':
+ b1 = style1.getBorderLeft() == BorderStyle.THIN;
+ b2 = style2.getBorderLeft() == BorderStyle.THIN;
+ borderName = "LEFT";
+ break;
+ case 'r':
+ b1 = style1.getBorderRight() == BorderStyle.THIN;
+ b2 = style2.getBorderRight() == BorderStyle.THIN;
+ borderName = "RIGHT";
+ break;
+ }
+ if (b1 != b2) {
+ addMessage(loc1, loc2,
+ "Cell Border Attributes does not Match ::",
+ (b1 ? "" : "NOT ")+borderName+" BORDER",
+ (b2 ? "" : "NOT ")+borderName+" BORDER"
+ );
+ }
+ }
+
+ /**
+ * Checks if cell content matches.
+ */
+ private void isCellContentMatches(Locator loc1, Locator loc2) {
+ String str1 = loc1.cell.toString();
+ String str2 = loc2.cell.toString();
+ if (!str1.equals(str2)) {
+ addMessage(loc1,loc2,CELL_DATA_DOES_NOT_MATCH,str1,str2);
+ }
+ }
+
+ /**
+ * Checks if cell content matches for boolean.
+ */
+ private void isCellContentMatchesForBoolean(Locator loc1, Locator loc2) {
+ boolean b1 = loc1.cell.getBooleanCellValue();
+ boolean b2 = loc2.cell.getBooleanCellValue();
+ if (b1 != b2) {
+ addMessage(loc1,loc2,CELL_DATA_DOES_NOT_MATCH,Boolean.toString(b1),Boolean.toString(b2));
+ }
+ }
+
+ /**
+ * Checks if cell content matches for date.
+ */
+ private void isCellContentMatchesForDate(Locator loc1, Locator loc2) {
+ Date date1 = loc1.cell.getDateCellValue();
+ Date date2 = loc2.cell.getDateCellValue();
+ if (!date1.equals(date2)) {
+ addMessage(loc1, loc2, CELL_DATA_DOES_NOT_MATCH, dateFormat.format(date1), dateFormat.format(date2));
+ }
+ }
+
+
+ /**
+ * Checks if cell content matches for formula.
+ */
+ private void isCellContentMatchesForFormula(Locator loc1, Locator loc2) {
+ // TODO: actually evaluate the formula / NPE checks
+ String form1 = loc1.cell.getCellFormula();
+ String form2 = loc2.cell.getCellFormula();
+ if (!form1.equals(form2)) {
+ addMessage(loc1, loc2, CELL_DATA_DOES_NOT_MATCH, form1, form2);
+ }
+ }
+
+ /**
+ * Checks if cell content matches for numeric.
+ */
+ private void isCellContentMatchesForNumeric(Locator loc1, Locator loc2) {
+ // TODO: Check for NaN
+ double num1 = loc1.cell.getNumericCellValue();
+ double num2 = loc2.cell.getNumericCellValue();
+ if (num1 != num2) {
+ addMessage(loc1, loc2, CELL_DATA_DOES_NOT_MATCH, Double.toString(num1), Double.toString(num2));
+ }
+ }
+
+ private String getCellFillBackground(Locator loc) {
+ Color col = loc.cell.getCellStyle().getFillForegroundColorColor();
+ return (col instanceof XSSFColor) ? ((XSSFColor)col).getARGBHex() : "NO COLOR";
+ }
+
+ /**
+ * Checks if cell file back ground matches.
+ */
+ private void isCellFillBackGroundMatches(Locator loc1, Locator loc2) {
+ if(loc1.cell.getCellStyle() == null || loc2.cell.getCellStyle() == null) {
+ return;
+ }
+
+ String col1 = getCellFillBackground(loc1);
+ String col2 = getCellFillBackground(loc2);
+ if (!Objects.equals(col1, col2)) {
+ addMessage(loc1, loc2, "Cell Fill Color does not Match ::", col1, col2);
+ }
+ }
+ /**
+ * Checks if cell fill pattern matches.
+ */
+ private void isCellFillPatternMatches(Locator loc1, Locator loc2) {
+ if(loc1.cell.getCellStyle() == null || loc2.cell.getCellStyle() == null) {
+ return;
+ }
+
+ FillPatternType fill1 = loc1.cell.getCellStyle().getFillPattern();
+ FillPatternType fill2 = loc2.cell.getCellStyle().getFillPattern();
+ if (fill1 != fill2) {
+ addMessage(loc1, loc2,
+ "Cell Fill pattern does not Match ::",
+ fill1.name(),
+ fill2.name()
+ );
+ }
+ }
+
+ /**
+ * Checks if cell font bold matches.
+ */
+ private void isCellFontBoldMatches(Locator loc1, Locator loc2) {
+ if (!(loc1.cell instanceof XSSFCell) ||
+ loc1.cell.getCellStyle() == null || loc2.cell.getCellStyle() == null) {
+ return;
+ }
+
+ if(hasInvalidFontIndex(loc1, loc2)) {
+ return;
+ }
+
+ boolean b1 = ((XSSFCell)loc1.cell).getCellStyle().getFont().getBold();
+ boolean b2 = ((XSSFCell)loc2.cell).getCellStyle().getFont().getBold();
+ if (b1 != b2) {
+ addMessage(loc1, loc2,
+ CELL_FONT_ATTRIBUTES_DOES_NOT_MATCH,
+ (b1 ? "" : "NOT ")+"BOLD",
+ (b2 ? "" : "NOT ")+"BOLD"
+ );
+ }
+ }
+
+ /**
+ * Checks if cell font family matches.
+ */
+ private void isCellFontFamilyMatches(Locator loc1, Locator loc2) {
+ if (!(loc1.cell instanceof XSSFCell) ||
+ loc1.cell.getCellStyle() == null || loc2.cell.getCellStyle() == null) {
+ return;
+ }
+
+ if(hasInvalidFontIndex(loc1, loc2)) {
+ return;
+ }
+
+ String family1 = ((XSSFCell)loc1.cell).getCellStyle().getFont().getFontName();
+ String family2 = ((XSSFCell)loc2.cell).getCellStyle().getFont().getFontName();
+ if (!family1.equals(family2)) {
+ addMessage(loc1, loc2, "Cell Font Family does not Match ::", family1, family2);
+ }
+ }
+
+ private boolean hasInvalidFontIndex(Locator loc1, Locator loc2) {
+ int fontIdx1 = loc1.cell.getCellStyle().getFontIndex();
+ int fontCount1 = ((XSSFWorkbook)loc1.workbook).getStylesSource().getFonts().size();
+ int fontIdx2 = loc2.cell.getCellStyle().getFontIndex();
+ int fontCount2 = ((XSSFWorkbook)loc2.workbook).getStylesSource().getFonts().size();
+
+ if(fontIdx1 >= fontCount1 || fontIdx2 >= fontCount2) {
+ addMessage(loc1, loc2, "Corrupted file, cell style references a font which is not defined", Integer.toString(fontIdx1), Integer.toString(fontIdx2));
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Checks if cell font italics matches.
+ */
+ private void isCellFontItalicsMatches(Locator loc1, Locator loc2) {
+ if (!(loc1.cell instanceof XSSFCell) ||
+ loc1.cell.getCellStyle() == null || loc2.cell.getCellStyle() == null) {
+ return;
+ }
+
+ if(hasInvalidFontIndex(loc1, loc2)) {
+ return;
+ }
+
+ boolean b1 = ((XSSFCell)loc1.cell).getCellStyle().getFont().getItalic();
+ boolean b2 = ((XSSFCell)loc2.cell).getCellStyle().getFont().getItalic();
+ if (b1 != b2) {
+ addMessage(loc1, loc2,
+ CELL_FONT_ATTRIBUTES_DOES_NOT_MATCH,
+ (b1 ? "" : "NOT ")+"ITALICS",
+ (b2 ? "" : "NOT ")+"ITALICS"
+ );
+ }
+ }
+
+ /**
+ * Checks if cell font size matches.
+ */
+ private void isCellFontSizeMatches(Locator loc1, Locator loc2) {
+ if (!(loc1.cell instanceof XSSFCell) ||
+ loc1.cell.getCellStyle() == null || loc2.cell.getCellStyle() == null) {
+ return;
+ }
+
+ if(hasInvalidFontIndex(loc1, loc2)) {
+ return;
+ }
+
+ short size1 = ((XSSFCell)loc1.cell).getCellStyle().getFont().getFontHeightInPoints();
+ short size2 = ((XSSFCell)loc2.cell).getCellStyle().getFont().getFontHeightInPoints();
+ if (size1 != size2) {
+ addMessage(loc1, loc2,
+ "Cell Font Size does not Match ::",
+ Short.toString(size1),
+ Short.toString(size2)
+ );
+ }
+ }
+
+ /**
+ * Checks if cell hidden matches.
+ */
+ private void isCellHiddenMatches(Locator loc1, Locator loc2) {
+ if (loc1.cell.getCellStyle() == null || loc2.cell.getCellStyle() == null) {
+ return;
+ }
+
+ boolean b1 = loc1.cell.getCellStyle().getHidden();
+ boolean b2 = loc1.cell.getCellStyle().getHidden();
+ if (b1 != b2) {
+ addMessage(loc1, loc2,
+ "Cell Visibility does not Match ::",
+ (b1 ? "" : "NOT ")+"HIDDEN",
+ (b2 ? "" : "NOT ")+"HIDDEN"
+ );
+ }
+ }
+
+ /**
+ * Checks if cell locked matches.
+ */
+ private void isCellLockedMatches(Locator loc1, Locator loc2) {
+ if (loc1.cell.getCellStyle() == null || loc2.cell.getCellStyle() == null) {
+ return;
+ }
+
+ boolean b1 = loc1.cell.getCellStyle().getLocked();
+ boolean b2 = loc1.cell.getCellStyle().getLocked();
+ if (b1 != b2) {
+ addMessage(loc1, loc2,
+ "Cell Protection does not Match ::",
+ (b1 ? "" : "NOT ")+"LOCKED",
+ (b2 ? "" : "NOT ")+"LOCKED"
+ );
+ }
+ }
+
+ /**
+ * Checks if cell type matches.
+ */
+ private boolean isCellTypeMatches(Locator loc1, Locator loc2) {
+ CellType type1 = loc1.cell.getCellType();
+ CellType type2 = loc2.cell.getCellType();
+ if (type1 == type2) {
+ return true;
+ }
+
+ addMessage(loc1, loc2,
+ "Cell Data-Type does not Match in :: ",
+ type1.name(), type2.name()
+ );
+ return false;
+ }
+
+ /**
+ * Checks if cell under line matches.
+ */
+ private void isCellUnderLineMatches(Locator loc1, Locator loc2) {
+ // TODO: distinguish underline type
+
+ if (!(loc1.cell instanceof XSSFCell) ||
+ loc1.cell.getCellStyle() == null || loc2.cell.getCellStyle() == null) {
+ return;
+ }
+
+ if(hasInvalidFontIndex(loc1, loc2)) {
+ return;
+ }
+
+ byte b1 = ((XSSFCell)loc1.cell).getCellStyle().getFont().getUnderline();
+ byte b2 = ((XSSFCell)loc2.cell).getCellStyle().getFont().getUnderline();
+ if (b1 != b2) {
+ addMessage(loc1, loc2,
+ CELL_FONT_ATTRIBUTES_DOES_NOT_MATCH,
+ (b1 == 1 ? "" : "NOT ")+"UNDERLINE",
+ (b2 == 1 ? "" : "NOT ")+"UNDERLINE"
+ );
+ }
+ }
+} \ No newline at end of file
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/ss/LinkedDropDownLists.java b/poi-examples/src/main/java/org/apache/poi/examples/ss/LinkedDropDownLists.java
new file mode 100644
index 0000000000..5cbc63be60
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/ss/LinkedDropDownLists.java
@@ -0,0 +1,206 @@
+ /* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ ==================================================================== */
+
+package org.apache.poi.examples.ss;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.DataValidation;
+import org.apache.poi.ss.usermodel.DataValidationConstraint;
+import org.apache.poi.ss.usermodel.DataValidationHelper;
+import org.apache.poi.ss.usermodel.Name;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.util.CellRangeAddressList;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Demonstrates one technique that may be used to create linked or dependent
+ * drop down lists. This refers to a situation in which the selection made
+ * in one drop down list affects the options that are displayed in the second
+ * or subsequent drop down list(s). In this example, the value the user selects
+ * from the down list in cell A1 will affect the values displayed in the linked
+ * drop down list in cell B1. For the sake of simplicity, the data for the drop
+ * down lists is included on the same worksheet but this does not have to be the
+ * case; the data could appear on a separate sheet. If this were done, then the
+ * names for the regions would have to be different, they would have to include
+ * the name of the sheet.
+ *
+ * There are two keys to this technique. The first is the use of named area or
+ * regions of cells to hold the data for the drop down lists and the second is
+ * making use of the INDIRECT() function to convert a name into the addresses
+ * of the cells it refers to.
+ *
+ * Note that whilst this class builds just two linked drop down lists, there is
+ * nothing to prevent more being created. Quite simply, use the value selected
+ * by the user in one drop down list to determine what is shown in another and the
+ * value selected in that drop down list to determine what is shown in a third,
+ * and so on. Also, note that the data for the drop down lists is contained on
+ * contained on the same sheet as the validations themselves. This is done simply
+ * for simplicity and there is nothing to prevent a separate sheet being created
+ * and used to hold the data. If this is done then problems may be encountered
+ * if the sheet is opened with OpenOffice Calc. To prevent these problems, it is
+ * better to include the name of the sheet when calling the setRefersToFormula()
+ * method.
+ *
+ * @author Mark Beardsley [msb at apache.org]
+ * @version 1.00 30th March 2012
+ */
+public class LinkedDropDownLists {
+
+ LinkedDropDownLists(String workbookName) throws IOException {
+ // Using the ss.usermodel allows this class to support both binary
+ // and xml based workbooks. The choice of which one to create is
+ // made by checking the file extension.
+ try (Workbook workbook = workbookName.endsWith(".xlsx") ? new XSSFWorkbook() : new HSSFWorkbook()) {
+
+ // Build the sheet that will hold the data for the validations. This
+ // must be done first as it will create names that are referenced
+ // later.
+ Sheet sheet = workbook.createSheet("Linked Validations");
+ LinkedDropDownLists.buildDataSheet(sheet);
+
+ // Build the first data validation to occupy cell A1. Note
+ // that it retrieves it's data from the named area or region called
+ // CHOICES. Further information about this can be found in the
+ // static buildDataSheet() method below.
+ CellRangeAddressList addressList = new CellRangeAddressList(0, 0, 0, 0);
+ DataValidationHelper dvHelper = sheet.getDataValidationHelper();
+ DataValidationConstraint dvConstraint = dvHelper.createFormulaListConstraint("CHOICES");
+ DataValidation validation = dvHelper.createValidation(dvConstraint, addressList);
+ sheet.addValidationData(validation);
+
+ // Now, build the linked or dependent drop down list that will
+ // occupy cell B1. The key to the whole process is the use of the
+ // INDIRECT() function. In the buildDataSheet(0 method, a series of
+ // named regions are created and the names of three of them mirror
+ // the options available to the user in the first drop down list
+ // (in cell A1). Using the INDIRECT() function makes it possible
+ // to convert the selection the user makes in that first drop down
+ // into the addresses of a named region of cells and then to use
+ // those cells to populate the second drop down list.
+ addressList = new CellRangeAddressList(0, 0, 1, 1);
+ dvConstraint = dvHelper.createFormulaListConstraint(
+ "INDIRECT(UPPER($A$1))");
+ validation = dvHelper.createValidation(dvConstraint, addressList);
+ sheet.addValidationData(validation);
+
+ try (FileOutputStream fos = new FileOutputStream(workbookName)) {
+ workbook.write(fos);
+ }
+ }
+ }
+
+ /**
+ * Called to populate the named areas/regions. The contents of the cells on
+ * row one will be used to populate the first drop down list. The contents of
+ * the cells on rows two, three and four will be used to populate the second
+ * drop down list, just which row will be determined by the choice the user
+ * makes in the first drop down list.
+ *
+ * In all cases, the approach is to create a row, create and populate cells
+ * with data and then specify a name that identifies those cells. With the
+ * exception of the first range, the names that are chosen for each range
+ * of cells are quite important. In short, each of the options the user
+ * could select in the first drop down list is used as the name for another
+ * range of cells. Thus, in this example, the user can select either
+ * 'Animal', 'Vegetable' or 'Mineral' in the first drop down and so the
+ * sheet contains ranges named 'ANIMAL', 'VEGETABLE' and 'MINERAL'.
+ *
+ * @param dataSheet An instance of a class that implements the Sheet Sheet
+ * interface (HSSFSheet or XSSFSheet).
+ */
+ private static void buildDataSheet(Sheet dataSheet) {
+ Row row = null;
+ Cell cell = null;
+ Name name = null;
+
+ // The first row will hold the data for the first validation.
+ row = dataSheet.createRow(10);
+ cell = row.createCell(0);
+ cell.setCellValue("Animal");
+ cell = row.createCell(1);
+ cell.setCellValue("Vegetable");
+ cell = row.createCell(2);
+ cell.setCellValue("Mineral");
+ name = dataSheet.getWorkbook().createName();
+ name.setRefersToFormula("$A$11:$C$11");
+ name.setNameName("CHOICES");
+
+ // The next three rows will hold the data that will be used to
+ // populate the second, or linked, drop down list.
+ row = dataSheet.createRow(11);
+ cell = row.createCell(0);
+ cell.setCellValue("Lion");
+ cell = row.createCell(1);
+ cell.setCellValue("Tiger");
+ cell = row.createCell(2);
+ cell.setCellValue("Leopard");
+ cell = row.createCell(3);
+ cell.setCellValue("Elephant");
+ cell = row.createCell(4);
+ cell.setCellValue("Eagle");
+ cell = row.createCell(5);
+ cell.setCellValue("Horse");
+ cell = row.createCell(6);
+ cell.setCellValue("Zebra");
+ name = dataSheet.getWorkbook().createName();
+ name.setRefersToFormula("$A$12:$G$12");
+ name.setNameName("ANIMAL");
+
+ row = dataSheet.createRow(12);
+ cell = row.createCell(0);
+ cell.setCellValue("Cabbage");
+ cell = row.createCell(1);
+ cell.setCellValue("Cauliflower");
+ cell = row.createCell(2);
+ cell.setCellValue("Potato");
+ cell = row.createCell(3);
+ cell.setCellValue("Onion");
+ cell = row.createCell(4);
+ cell.setCellValue("Beetroot");
+ cell = row.createCell(5);
+ cell.setCellValue("Asparagus");
+ cell = row.createCell(6);
+ cell.setCellValue("Spinach");
+ cell = row.createCell(7);
+ cell.setCellValue("Chard");
+ name = dataSheet.getWorkbook().createName();
+ name.setRefersToFormula("$A$13:$H$13");
+ name.setNameName("VEGETABLE");
+
+ row = dataSheet.createRow(13);
+ cell = row.createCell(0);
+ cell.setCellValue("Bauxite");
+ cell = row.createCell(1);
+ cell.setCellValue("Quartz");
+ cell = row.createCell(2);
+ cell.setCellValue("Feldspar");
+ cell = row.createCell(3);
+ cell.setCellValue("Shist");
+ cell = row.createCell(4);
+ cell.setCellValue("Shale");
+ cell = row.createCell(5);
+ cell.setCellValue("Mica");
+ name = dataSheet.getWorkbook().createName();
+ name.setRefersToFormula("$A$14:$F$14");
+ name.setNameName("MINERAL");
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/ss/LoadEmbedded.java b/poi-examples/src/main/java/org/apache/poi/examples/ss/LoadEmbedded.java
new file mode 100644
index 0000000000..3c52ecf253
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/ss/LoadEmbedded.java
@@ -0,0 +1,134 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.ss;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.poi.EncryptedDocumentException;
+import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+import org.apache.poi.hssf.usermodel.HSSFObjectData;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hwpf.HWPFDocument;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
+import org.apache.poi.openxml4j.opc.PackagePart;
+import org.apache.poi.poifs.filesystem.DirectoryNode;
+import org.apache.poi.poifs.filesystem.Entry;
+import org.apache.poi.sl.usermodel.SlideShow;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.usermodel.WorkbookFactory;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.apache.xmlbeans.XmlException;
+
+/**
+ * Loads embedded resources from Workbooks. Code taken from the website:
+ * https://poi.apache.org/spreadsheet/quick-guide.html#Embedded
+ */
+@SuppressWarnings({"java:S106","java:S4823"})
+public final class LoadEmbedded {
+ private LoadEmbedded() {}
+
+ public static void main(String[] args) throws IOException, EncryptedDocumentException, OpenXML4JException, XmlException {
+ Workbook wb = WorkbookFactory.create(new File(args[0]));
+ loadEmbedded(wb);
+ }
+
+ public static void loadEmbedded(Workbook wb) throws IOException, InvalidFormatException, OpenXML4JException, XmlException {
+ if (wb instanceof HSSFWorkbook) {
+ loadEmbedded((HSSFWorkbook)wb);
+ }
+ else if (wb instanceof XSSFWorkbook) {
+ loadEmbedded((XSSFWorkbook)wb);
+ }
+ else {
+ throw new IllegalArgumentException(wb.getClass().getName());
+ }
+ }
+
+ public static void loadEmbedded(HSSFWorkbook workbook) throws IOException {
+ for (HSSFObjectData obj : workbook.getAllEmbeddedObjects()) {
+ //the OLE2 Class Name of the object
+ String oleName = obj.getOLE2ClassName();
+ if (oleName.equals("Worksheet")) {
+ DirectoryNode dn = (DirectoryNode) obj.getDirectory();
+ HSSFWorkbook embeddedWorkbook = new HSSFWorkbook(dn, false);
+ embeddedWorkbook.close();
+ } else if (oleName.equals("Document")) {
+ DirectoryNode dn = (DirectoryNode) obj.getDirectory();
+ HWPFDocument embeddedWordDocument = new HWPFDocument(dn);
+ embeddedWordDocument.close();
+ } else if (oleName.equals("Presentation")) {
+ DirectoryNode dn = (DirectoryNode) obj.getDirectory();
+ SlideShow<?,?> embeddedSlieShow = new HSLFSlideShow(dn);
+ embeddedSlieShow.close();
+ } else {
+ if(obj.hasDirectoryEntry()){
+ // The DirectoryEntry is a DocumentNode. Examine its entries to find out what it is
+ DirectoryNode dn = (DirectoryNode) obj.getDirectory();
+ for (Entry entry : dn) {
+ //System.out.println(oleName + "." + entry.getName());
+ }
+ } else {
+ // There is no DirectoryEntry
+ // Recover the object's data from the HSSFObjectData instance.
+ byte[] objectData = obj.getObjectData();
+ }
+ }
+ }
+ }
+
+ public static void loadEmbedded(XSSFWorkbook workbook) throws IOException, InvalidFormatException, OpenXML4JException, XmlException {
+ for (PackagePart pPart : workbook.getAllEmbeddedParts()) {
+ String contentType = pPart.getContentType();
+ if (contentType.equals("application/vnd.ms-excel")) {
+ // Excel Workbook - either binary or OpenXML
+ HSSFWorkbook embeddedWorkbook = new HSSFWorkbook(pPart.getInputStream());
+ embeddedWorkbook.close();
+ } else if (contentType.equals("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")) {
+ // Excel Workbook - OpenXML file format
+ XSSFWorkbook embeddedWorkbook = new XSSFWorkbook(pPart.getInputStream());
+ embeddedWorkbook.close();
+ } else if (contentType.equals("application/msword")) {
+ // Word Document - binary (OLE2CDF) file format
+ HWPFDocument document = new HWPFDocument(pPart.getInputStream());
+ document.close();
+ } else if (contentType.equals("application/vnd.openxmlformats-officedocument.wordprocessingml.document")) {
+ // Word Document - OpenXML file format
+ XWPFDocument document = new XWPFDocument(pPart.getInputStream());
+ document.close();
+ } else if (contentType.equals("application/vnd.ms-powerpoint")) {
+ // PowerPoint Document - binary file format
+ HSLFSlideShow slideShow = new HSLFSlideShow(pPart.getInputStream());
+ slideShow.close();
+ } else if (contentType.equals("application/vnd.openxmlformats-officedocument.presentationml.presentation")) {
+ // PowerPoint Document - OpenXML file format
+ XMLSlideShow slideShow = new XMLSlideShow(pPart.getInputStream());
+ slideShow.close();
+ } else {
+ // Any other type of embedded object.
+ System.out.println("Unknown Embedded Document: " + contentType);
+ InputStream inputStream = pPart.getInputStream();
+ inputStream.close();
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/ss/LoanCalculator.java b/poi-examples/src/main/java/org/apache/poi/examples/ss/LoanCalculator.java
new file mode 100644
index 0000000000..28d1c648f0
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/ss/LoanCalculator.java
@@ -0,0 +1,319 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.ss;
+
+import java.io.FileOutputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.usermodel.Name;
+import org.apache.poi.ss.usermodel.PrintSetup;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Simple Loan Calculator. Demonstrates advance usage of cell formulas and named ranges.
+ *
+ * Usage:
+ * LoanCalculator -xls|xlsx
+ *
+ * @author Yegor Kozlov
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class LoanCalculator {
+
+ private LoanCalculator() {}
+
+ public static void main(String[] args) throws Exception {
+ Workbook wb;
+
+ if(args.length > 0 && args[0].equals("-xls")) wb = new HSSFWorkbook();
+ else wb = new XSSFWorkbook();
+
+ Map<String, CellStyle> styles = createStyles(wb);
+ Sheet sheet = wb.createSheet("Loan Calculator");
+ sheet.setPrintGridlines(false);
+ sheet.setDisplayGridlines(false);
+
+ PrintSetup printSetup = sheet.getPrintSetup();
+ printSetup.setLandscape(true);
+ sheet.setFitToPage(true);
+ sheet.setHorizontallyCenter(true);
+
+ sheet.setColumnWidth(0, 3*256);
+ sheet.setColumnWidth(1, 3*256);
+ sheet.setColumnWidth(2, 11*256);
+ sheet.setColumnWidth(3, 14*256);
+ sheet.setColumnWidth(4, 14*256);
+ sheet.setColumnWidth(5, 14*256);
+ sheet.setColumnWidth(6, 14*256);
+
+ createNames(wb);
+
+ Row titleRow = sheet.createRow(0);
+ titleRow.setHeightInPoints(35);
+ for (int i = 1; i <= 7; i++) {
+ titleRow.createCell(i).setCellStyle(styles.get("title"));
+ }
+ Cell titleCell = titleRow.getCell(2);
+ titleCell.setCellValue("Simple Loan Calculator");
+ sheet.addMergedRegion(CellRangeAddress.valueOf("$C$1:$H$1"));
+
+ Row row = sheet.createRow(2);
+ Cell cell = row.createCell(4);
+ cell.setCellValue("Enter values");
+ cell.setCellStyle(styles.get("item_right"));
+
+ row = sheet.createRow(3);
+ cell = row.createCell(2);
+ cell.setCellValue("Loan amount");
+ cell.setCellStyle(styles.get("item_left"));
+ cell = row.createCell(4);
+ cell.setCellStyle(styles.get("input_$"));
+ cell.setAsActiveCell();
+
+ row = sheet.createRow(4);
+ cell = row.createCell(2);
+ cell.setCellValue("Annual interest rate");
+ cell.setCellStyle(styles.get("item_left"));
+ cell = row.createCell(4);
+ cell.setCellStyle(styles.get("input_%"));
+
+ row = sheet.createRow(5);
+ cell = row.createCell(2);
+ cell.setCellValue("Loan period in years");
+ cell.setCellStyle(styles.get("item_left"));
+ cell = row.createCell(4);
+ cell.setCellStyle(styles.get("input_i"));
+
+ row = sheet.createRow(6);
+ cell = row.createCell(2);
+ cell.setCellValue("Start date of loan");
+ cell.setCellStyle(styles.get("item_left"));
+ cell = row.createCell(4);
+ cell.setCellStyle(styles.get("input_d"));
+
+ row = sheet.createRow(8);
+ cell = row.createCell(2);
+ cell.setCellValue("Monthly payment");
+ cell.setCellStyle(styles.get("item_left"));
+ cell = row.createCell(4);
+ cell.setCellFormula("IF(Values_Entered,Monthly_Payment,\"\")");
+ cell.setCellStyle(styles.get("formula_$"));
+
+ row = sheet.createRow(9);
+ cell = row.createCell(2);
+ cell.setCellValue("Number of payments");
+ cell.setCellStyle(styles.get("item_left"));
+ cell = row.createCell(4);
+ cell.setCellFormula("IF(Values_Entered,Loan_Years*12,\"\")");
+ cell.setCellStyle(styles.get("formula_i"));
+
+ row = sheet.createRow(10);
+ cell = row.createCell(2);
+ cell.setCellValue("Total interest");
+ cell.setCellStyle(styles.get("item_left"));
+ cell = row.createCell(4);
+ cell.setCellFormula("IF(Values_Entered,Total_Cost-Loan_Amount,\"\")");
+ cell.setCellStyle(styles.get("formula_$"));
+
+ row = sheet.createRow(11);
+ cell = row.createCell(2);
+ cell.setCellValue("Total cost of loan");
+ cell.setCellStyle(styles.get("item_left"));
+ cell = row.createCell(4);
+ cell.setCellFormula("IF(Values_Entered,Monthly_Payment*Number_of_Payments,\"\")");
+ cell.setCellStyle(styles.get("formula_$"));
+
+
+ // Write the output to a file
+ String file = "loan-calculator.xls";
+ if(wb instanceof XSSFWorkbook) file += "x";
+ FileOutputStream out = new FileOutputStream(file);
+ wb.write(out);
+ out.close();
+ }
+
+ /**
+ * cell styles used for formatting calendar sheets
+ */
+ private static Map<String, CellStyle> createStyles(Workbook wb){
+ Map<String, CellStyle> styles = new HashMap<>();
+
+ CellStyle style;
+ Font titleFont = wb.createFont();
+ titleFont.setFontHeightInPoints((short)14);
+ titleFont.setFontName("Trebuchet MS");
+ style = wb.createCellStyle();
+ style.setFont(titleFont);
+ style.setBorderBottom(BorderStyle.DOTTED);
+ style.setBottomBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+ styles.put("title", style);
+
+ Font itemFont = wb.createFont();
+ itemFont.setFontHeightInPoints((short)9);
+ itemFont.setFontName("Trebuchet MS");
+ style = wb.createCellStyle();
+ style.setAlignment(HorizontalAlignment.LEFT);
+ style.setFont(itemFont);
+ styles.put("item_left", style);
+
+ style = wb.createCellStyle();
+ style.setAlignment(HorizontalAlignment.RIGHT);
+ style.setFont(itemFont);
+ styles.put("item_right", style);
+
+ style = wb.createCellStyle();
+ style.setAlignment(HorizontalAlignment.RIGHT);
+ style.setFont(itemFont);
+ style.setBorderRight(BorderStyle.DOTTED);
+ style.setRightBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+ style.setBorderBottom(BorderStyle.DOTTED);
+ style.setBottomBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+ style.setBorderLeft(BorderStyle.DOTTED);
+ style.setLeftBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+ style.setBorderTop(BorderStyle.DOTTED);
+ style.setTopBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+ style.setDataFormat(wb.createDataFormat().getFormat("_($* #,##0.00_);_($* (#,##0.00);_($* \"-\"??_);_(@_)"));
+ styles.put("input_$", style);
+
+ style = wb.createCellStyle();
+ style.setAlignment(HorizontalAlignment.RIGHT);
+ style.setFont(itemFont);
+ style.setBorderRight(BorderStyle.DOTTED);
+ style.setRightBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+ style.setBorderBottom(BorderStyle.DOTTED);
+ style.setBottomBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+ style.setBorderLeft(BorderStyle.DOTTED);
+ style.setLeftBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+ style.setBorderTop(BorderStyle.DOTTED);
+ style.setTopBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+ style.setDataFormat(wb.createDataFormat().getFormat("0.000%"));
+ styles.put("input_%", style);
+
+ style = wb.createCellStyle();
+ style.setAlignment(HorizontalAlignment.RIGHT);
+ style.setFont(itemFont);
+ style.setBorderRight(BorderStyle.DOTTED);
+ style.setRightBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+ style.setBorderBottom(BorderStyle.DOTTED);
+ style.setBottomBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+ style.setBorderLeft(BorderStyle.DOTTED);
+ style.setLeftBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+ style.setBorderTop(BorderStyle.DOTTED);
+ style.setTopBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+ style.setDataFormat(wb.createDataFormat().getFormat("0"));
+ styles.put("input_i", style);
+
+ style = wb.createCellStyle();
+ style.setAlignment(HorizontalAlignment.CENTER);
+ style.setFont(itemFont);
+ style.setDataFormat(wb.createDataFormat().getFormat("m/d/yy"));
+ styles.put("input_d", style);
+
+ style = wb.createCellStyle();
+ style.setAlignment(HorizontalAlignment.RIGHT);
+ style.setFont(itemFont);
+ style.setBorderRight(BorderStyle.DOTTED);
+ style.setRightBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+ style.setBorderBottom(BorderStyle.DOTTED);
+ style.setBottomBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+ style.setBorderLeft(BorderStyle.DOTTED);
+ style.setLeftBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+ style.setBorderTop(BorderStyle.DOTTED);
+ style.setTopBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+ style.setDataFormat(wb.createDataFormat().getFormat("$##,##0.00"));
+ style.setBorderBottom(BorderStyle.DOTTED);
+ style.setBottomBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+ style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+ styles.put("formula_$", style);
+
+ style = wb.createCellStyle();
+ style.setAlignment(HorizontalAlignment.RIGHT);
+ style.setFont(itemFont);
+ style.setBorderRight(BorderStyle.DOTTED);
+ style.setRightBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+ style.setBorderBottom(BorderStyle.DOTTED);
+ style.setBottomBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+ style.setBorderLeft(BorderStyle.DOTTED);
+ style.setLeftBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+ style.setBorderTop(BorderStyle.DOTTED);
+ style.setTopBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+ style.setDataFormat(wb.createDataFormat().getFormat("0"));
+ style.setBorderBottom(BorderStyle.DOTTED);
+ style.setBottomBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
+ style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+ styles.put("formula_i", style);
+
+ return styles;
+ }
+
+ //define named ranges for the inputs and formulas
+ public static void createNames(Workbook wb){
+ Name name;
+
+ name = wb.createName();
+ name.setNameName("Interest_Rate");
+ name.setRefersToFormula("'Loan Calculator'!$E$5");
+
+ name = wb.createName();
+ name.setNameName("Loan_Amount");
+ name.setRefersToFormula("'Loan Calculator'!$E$4");
+
+ name = wb.createName();
+ name.setNameName("Loan_Start");
+ name.setRefersToFormula("'Loan Calculator'!$E$7");
+
+ name = wb.createName();
+ name.setNameName("Loan_Years");
+ name.setRefersToFormula("'Loan Calculator'!$E$6");
+
+ name = wb.createName();
+ name.setNameName("Number_of_Payments");
+ name.setRefersToFormula("'Loan Calculator'!$E$10");
+
+ name = wb.createName();
+ name.setNameName("Monthly_Payment");
+ name.setRefersToFormula("-PMT(Interest_Rate/12,Number_of_Payments,Loan_Amount)");
+
+ name = wb.createName();
+ name.setNameName("Total_Cost");
+ name.setRefersToFormula("'Loan Calculator'!$E$12");
+
+ name = wb.createName();
+ name.setNameName("Total_Interest");
+ name.setRefersToFormula("'Loan Calculator'!$E$11");
+
+ name = wb.createName();
+ name.setNameName("Values_Entered");
+ name.setRefersToFormula("IF(Loan_Amount*Interest_Rate*Loan_Years*Loan_Start>0,1,0)");
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/ss/SSPerformanceTest.java b/poi-examples/src/main/java/org/apache/poi/examples/ss/SSPerformanceTest.java
new file mode 100644
index 0000000000..c041509d45
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/ss/SSPerformanceTest.java
@@ -0,0 +1,256 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+package org.apache.poi.examples.ss;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ooxml.POIXMLTypeLoader;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.VerticalAlignment;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.util.LocaleUtil;
+import org.apache.poi.xssf.streaming.SXSSFWorkbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class SSPerformanceTest {
+ private SSPerformanceTest() {}
+
+ public static void main(String[] args) throws IOException {
+ if (args.length < 4) {
+ usage("need at least four command arguments");
+ }
+
+ String type = args[0];
+ int rows = parseInt(args[1], "Failed to parse rows value as integer");
+ int cols = parseInt(args[2], "Failed to parse cols value as integer");
+ boolean saveFile = parseInt(args[3], "Failed to parse saveFile value as integer") != 0;
+
+ boolean warmup = false;
+ for(int arg = 4; arg < args.length;arg++) {
+ if(args[arg].equals("--unsynchronized-xmlbeans")) {
+ POIXMLTypeLoader.DEFAULT_XML_OPTIONS.setUnsynchronized();
+ }
+ if(args[arg].equals("--with-warmup-run")) {
+ warmup = true;
+ }
+ }
+
+ if(warmup) {
+ System.out.println("Performing a warmup run first");
+ runWithArgs(type, rows, cols, saveFile);
+ }
+
+ long timeStarted = System.currentTimeMillis();
+ runWithArgs(type, rows, cols, saveFile);
+ long timeFinished = System.currentTimeMillis();
+
+ System.out.printf(Locale.ROOT, "Elapsed %.2f seconds for arguments %s\n", ((double)timeFinished - timeStarted) / 1000, Arrays.toString(args));
+ }
+
+ private static void runWithArgs(String type, int rows, int cols, boolean saveFile) throws IOException {
+ try (Workbook workBook = createWorkbook(type)) {
+ boolean isHType = workBook instanceof HSSFWorkbook;
+ addContent(workBook, isHType, rows, cols);
+
+ if (saveFile) {
+ String fileName = type + "_" + rows + "_" + cols + "." + getFileSuffix(type);
+ saveFile(workBook, fileName);
+ }
+ }
+ }
+
+ private static void addContent(Workbook workBook, boolean isHType, int rows, int cols) {
+ Map<String, CellStyle> styles = createStyles(workBook);
+
+ Sheet sheet = workBook.createSheet("Main Sheet");
+
+ Cell headerCell = sheet.createRow(0).createCell(0);
+ headerCell.setCellValue("Header text is spanned across multiple cells");
+ headerCell.setCellStyle(styles.get("header"));
+ sheet.addMergedRegion(CellRangeAddress.valueOf("$A$1:$F$1"));
+
+ int sheetNo = 0;
+ int rowIndexInSheet = 1;
+ double value = 0;
+ Calendar calendar = LocaleUtil.getLocaleCalendar();
+ for (int rowIndex = 0; rowIndex < rows; rowIndex++) {
+ if (isHType && sheetNo != rowIndex / 0x10000) {
+ sheet = workBook.createSheet("Spillover from sheet " + (++sheetNo));
+ headerCell.setCellValue("Header text is spanned across multiple cells");
+ headerCell.setCellStyle(styles.get("header"));
+ sheet.addMergedRegion(CellRangeAddress.valueOf("$A$1:$F$1"));
+ rowIndexInSheet = 1;
+ }
+
+ Row row = sheet.createRow(rowIndexInSheet);
+ for (int colIndex = 0; colIndex < cols; colIndex++) {
+ value = populateCell(styles, value, calendar, rowIndex, row, colIndex);
+ }
+ rowIndexInSheet++;
+ }
+ }
+
+ private static double populateCell(Map<String, CellStyle> styles, double value, Calendar calendar, int rowIndex, Row row, int colIndex) {
+ Cell cell = row.createCell(colIndex);
+ String address = new CellReference(cell).formatAsString();
+ switch (colIndex){
+ case 0:
+ // column A: default number format
+ cell.setCellValue(value++);
+ break;
+ case 1:
+ // column B: #,##0
+ cell.setCellValue(value++);
+ cell.setCellStyle(styles.get("#,##0.00"));
+ break;
+ case 2:
+ // column C: $#,##0.00
+ cell.setCellValue(value++);
+ cell.setCellStyle(styles.get("$#,##0.00"));
+ break;
+ case 3:
+ // column D: red bold text on yellow background
+ cell.setCellValue(address);
+ cell.setCellStyle(styles.get("red-bold"));
+ break;
+ case 4:
+ // column E: boolean
+ // TODO booleans are shown as 1/0 instead of TRUE/FALSE
+ cell.setCellValue(rowIndex % 2 == 0);
+ break;
+ case 5:
+ // column F: date / time
+ cell.setCellValue(calendar);
+ cell.setCellStyle(styles.get("m/d/yyyy"));
+ calendar.roll(Calendar.DAY_OF_YEAR, -1);
+ break;
+ case 6:
+ // column F: formula
+ // TODO formulas are not yet supported in SXSSF
+ //cell.setCellFormula("SUM(A" + (rowIndex+1) + ":E" + (rowIndex+1)+ ")");
+ //break;
+ default:
+ cell.setCellValue(value++);
+ break;
+ }
+ return value;
+ }
+
+ private static void saveFile(Workbook workBook, String fileName) {
+ try {
+ FileOutputStream out = new FileOutputStream(fileName);
+ workBook.write(out);
+ out.close();
+ } catch (IOException ioe) {
+ System.err.println("Error: failed to write to file \"" + fileName + "\", reason=" + ioe.getMessage());
+ }
+ }
+
+ static Map<String, CellStyle> createStyles(Workbook wb) {
+ Map<String, CellStyle> styles = new HashMap<>();
+ CellStyle style;
+
+ Font headerFont = wb.createFont();
+ headerFont.setFontHeightInPoints((short) 14);
+ headerFont.setBold(true);
+ style = wb.createCellStyle();
+ style.setAlignment(HorizontalAlignment.CENTER);
+ style.setVerticalAlignment(VerticalAlignment.CENTER);
+ style.setFont(headerFont);
+ style.setFillForegroundColor(IndexedColors.LIGHT_CORNFLOWER_BLUE.getIndex());
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+ styles.put("header", style);
+
+ Font monthFont = wb.createFont();
+ monthFont.setFontHeightInPoints((short)12);
+ monthFont.setColor(IndexedColors.RED.getIndex());
+ monthFont.setBold(true);
+ style = wb.createCellStyle();
+ style.setAlignment(HorizontalAlignment.CENTER);
+ style.setVerticalAlignment(VerticalAlignment.CENTER);
+ style.setFillForegroundColor(IndexedColors.YELLOW.getIndex());
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+ style.setFont(monthFont);
+ styles.put("red-bold", style);
+
+ String[] nfmt = {"#,##0.00", "$#,##0.00", "m/d/yyyy"};
+ for(String fmt : nfmt){
+ style = wb.createCellStyle();
+ style.setDataFormat(wb.createDataFormat().getFormat(fmt));
+ styles.put(fmt, style);
+ }
+
+ return styles;
+ }
+
+
+ static void usage(String message) {
+ System.err.println(message);
+ System.err.println("usage: java SSPerformanceTest HSSF|XSSF|SXSSF rows cols saveFile (0|1)? [--unsynchronized-xmlbeans] [--with-warmup-run]");
+ System.exit(1);
+ }
+
+ static Workbook createWorkbook(String type) {
+ if ("HSSF".equals(type))
+ return new HSSFWorkbook();
+ else if ("XSSF".equals(type))
+ return new XSSFWorkbook();
+ else if ("SXSSF".equals(type))
+ return new SXSSFWorkbook();
+
+ usage("Unknown type \"" + type + "\"");
+ throw new IllegalArgumentException("Should not reach this point");
+ }
+
+ static String getFileSuffix(String type) {
+ if ("HSSF".equals(type))
+ return "xls";
+ else if ("XSSF".equals(type))
+ return "xlsx";
+ else if ("SXSSF".equals(type))
+ return "xlsx";
+ return null;
+ }
+
+ static int parseInt(String value, String msg) {
+ try {
+ return Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ usage(msg);
+ }
+ return 0;
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/ss/TimesheetDemo.java b/poi-examples/src/main/java/org/apache/poi/examples/ss/TimesheetDemo.java
new file mode 100644
index 0000000000..77b55c826d
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/ss/TimesheetDemo.java
@@ -0,0 +1,234 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.ss;
+
+import java.io.FileOutputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.usermodel.PrintSetup;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.VerticalAlignment;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * A weekly timesheet created using Apache POI.
+ * Usage:
+ * TimesheetDemo -xls|xlsx
+ *
+ * @author Yegor Kozlov
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class TimesheetDemo {
+ private static final String[] titles = {
+ "Person", "ID", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun",
+ "Total\nHrs", "Overtime\nHrs", "Regular\nHrs"
+ };
+
+ private static final Object[][] sample_data = {
+ {"Yegor Kozlov", "YK", 5.0, 8.0, 10.0, 5.0, 5.0, 7.0, 6.0},
+ {"Gisella Bronzetti", "GB", 4.0, 3.0, 1.0, 3.5, null, null, 4.0},
+ };
+
+ private TimesheetDemo() {}
+
+ public static void main(String[] args) throws Exception {
+ Workbook wb;
+
+ if(args.length > 0 && args[0].equals("-xls")) wb = new HSSFWorkbook();
+ else wb = new XSSFWorkbook();
+
+ Map<String, CellStyle> styles = createStyles(wb);
+
+ Sheet sheet = wb.createSheet("Timesheet");
+ PrintSetup printSetup = sheet.getPrintSetup();
+ printSetup.setLandscape(true);
+ sheet.setFitToPage(true);
+ sheet.setHorizontallyCenter(true);
+
+ //title row
+ Row titleRow = sheet.createRow(0);
+ titleRow.setHeightInPoints(45);
+ Cell titleCell = titleRow.createCell(0);
+ titleCell.setCellValue("Weekly Timesheet");
+ titleCell.setCellStyle(styles.get("title"));
+ sheet.addMergedRegion(CellRangeAddress.valueOf("$A$1:$L$1"));
+
+ //header row
+ Row headerRow = sheet.createRow(1);
+ headerRow.setHeightInPoints(40);
+ Cell headerCell;
+ for (int i = 0; i < titles.length; i++) {
+ headerCell = headerRow.createCell(i);
+ headerCell.setCellValue(titles[i]);
+ headerCell.setCellStyle(styles.get("header"));
+ }
+
+ int rownum = 2;
+ for (int i = 0; i < 10; i++) {
+ Row row = sheet.createRow(rownum++);
+ for (int j = 0; j < titles.length; j++) {
+ Cell cell = row.createCell(j);
+ if(j == 9){
+ //the 10th cell contains sum over week days, e.g. SUM(C3:I3)
+ String ref = "C" +rownum+ ":I" + rownum;
+ cell.setCellFormula("SUM("+ref+")");
+ cell.setCellStyle(styles.get("formula"));
+ } else if (j == 11){
+ cell.setCellFormula("J" +rownum+ "-K" + rownum);
+ cell.setCellStyle(styles.get("formula"));
+ } else {
+ cell.setCellStyle(styles.get("cell"));
+ }
+ }
+ }
+
+ //row with totals below
+ Row sumRow = sheet.createRow(rownum++);
+ sumRow.setHeightInPoints(35);
+ Cell cell;
+ cell = sumRow.createCell(0);
+ cell.setCellStyle(styles.get("formula"));
+ cell = sumRow.createCell(1);
+ cell.setCellValue("Total Hrs:");
+ cell.setCellStyle(styles.get("formula"));
+
+ for (int j = 2; j < 12; j++) {
+ cell = sumRow.createCell(j);
+ String ref = (char)('A' + j) + "3:" + (char)('A' + j) + "12";
+ cell.setCellFormula("SUM(" + ref + ")");
+ if(j >= 9) cell.setCellStyle(styles.get("formula_2"));
+ else cell.setCellStyle(styles.get("formula"));
+ }
+ rownum++;
+ sumRow = sheet.createRow(rownum++);
+ sumRow.setHeightInPoints(25);
+ cell = sumRow.createCell(0);
+ cell.setCellValue("Total Regular Hours");
+ cell.setCellStyle(styles.get("formula"));
+ cell = sumRow.createCell(1);
+ cell.setCellFormula("L13");
+ cell.setCellStyle(styles.get("formula_2"));
+ sumRow = sheet.createRow(rownum++);
+ sumRow.setHeightInPoints(25);
+ cell = sumRow.createCell(0);
+ cell.setCellValue("Total Overtime Hours");
+ cell.setCellStyle(styles.get("formula"));
+ cell = sumRow.createCell(1);
+ cell.setCellFormula("K13");
+ cell.setCellStyle(styles.get("formula_2"));
+
+ //set sample data
+ for (int i = 0; i < sample_data.length; i++) {
+ Row row = sheet.getRow(2 + i);
+ for (int j = 0; j < sample_data[i].length; j++) {
+ if(sample_data[i][j] == null) continue;
+
+ if(sample_data[i][j] instanceof String) {
+ row.getCell(j).setCellValue((String)sample_data[i][j]);
+ } else {
+ row.getCell(j).setCellValue((Double)sample_data[i][j]);
+ }
+ }
+ }
+
+ //finally set column widths, the width is measured in units of 1/256th of a character width
+ sheet.setColumnWidth(0, 30*256); //30 characters wide
+ for (int i = 2; i < 9; i++) {
+ sheet.setColumnWidth(i, 6*256); //6 characters wide
+ }
+ sheet.setColumnWidth(10, 10*256); //10 characters wide
+
+ // Write the output to a file
+ String file = "timesheet.xls";
+ if(wb instanceof XSSFWorkbook) file += "x";
+ FileOutputStream out = new FileOutputStream(file);
+ wb.write(out);
+ out.close();
+ }
+
+ /**
+ * Create a library of cell styles
+ */
+ private static Map<String, CellStyle> createStyles(Workbook wb){
+ Map<String, CellStyle> styles = new HashMap<>();
+ CellStyle style;
+ Font titleFont = wb.createFont();
+ titleFont.setFontHeightInPoints((short)18);
+ titleFont.setBold(true);
+ style = wb.createCellStyle();
+ style.setAlignment(HorizontalAlignment.CENTER);
+ style.setVerticalAlignment(VerticalAlignment.CENTER);
+ style.setFont(titleFont);
+ styles.put("title", style);
+
+ Font monthFont = wb.createFont();
+ monthFont.setFontHeightInPoints((short)11);
+ monthFont.setColor(IndexedColors.WHITE.getIndex());
+ style = wb.createCellStyle();
+ style.setAlignment(HorizontalAlignment.CENTER);
+ style.setVerticalAlignment(VerticalAlignment.CENTER);
+ style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex());
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+ style.setFont(monthFont);
+ style.setWrapText(true);
+ styles.put("header", style);
+
+ style = wb.createCellStyle();
+ style.setAlignment(HorizontalAlignment.CENTER);
+ style.setWrapText(true);
+ style.setBorderRight(BorderStyle.THIN);
+ style.setRightBorderColor(IndexedColors.BLACK.getIndex());
+ style.setBorderLeft(BorderStyle.THIN);
+ style.setLeftBorderColor(IndexedColors.BLACK.getIndex());
+ style.setBorderTop(BorderStyle.THIN);
+ style.setTopBorderColor(IndexedColors.BLACK.getIndex());
+ style.setBorderBottom(BorderStyle.THIN);
+ style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
+ styles.put("cell", style);
+
+ style = wb.createCellStyle();
+ style.setAlignment(HorizontalAlignment.CENTER);
+ style.setVerticalAlignment(VerticalAlignment.CENTER);
+ style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+ style.setDataFormat(wb.createDataFormat().getFormat("0.00"));
+ styles.put("formula", style);
+
+ style = wb.createCellStyle();
+ style.setAlignment(HorizontalAlignment.CENTER);
+ style.setVerticalAlignment(VerticalAlignment.CENTER);
+ style.setFillForegroundColor(IndexedColors.GREY_40_PERCENT.getIndex());
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+ style.setDataFormat(wb.createDataFormat().getFormat("0.00"));
+ styles.put("formula_2", style);
+
+ return styles;
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/ss/ToCSV.java b/poi-examples/src/main/java/org/apache/poi/examples/ss/ToCSV.java
new file mode 100644
index 0000000000..1c39838cd3
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/ss/ToCSV.java
@@ -0,0 +1,740 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.ss;
+
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.util.ArrayList;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.ss.usermodel.DataFormatter;
+import org.apache.poi.ss.usermodel.FormulaEvaluator;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.usermodel.WorkbookFactory;
+
+/**
+ * Demonstrates <em>one</em> way to convert an Excel spreadsheet into a CSV
+ * file. This class makes the following assumptions;
+ * <ul>
+ * <li>1. Where the Excel workbook contains more than one worksheet, then a single
+ * CSV file will contain the data from all of the worksheets.</li>
+ * <li>2. The data matrix contained in the CSV file will be square. This means that
+ * the number of fields in each record of the CSV file will match the number
+ * of cells in the longest row found in the Excel workbook. Any short records
+ * will be 'padded' with empty fields - an empty field is represented in
+ * the CSV file in this way - ,,.</li>
+ * <li>3. Empty fields will represent missing cells.</li>
+ * <li>4. A record consisting of empty fields will be used to represent an empty row
+ * in the Excel workbook.</li>
+ * </ul>
+ * Therefore, if the worksheet looked like this;
+ *
+ * <pre>
+ * ___________________________________________
+ * | | | | | |
+ * | A | B | C | D | E |
+ * ___|_______|_______|_______|_______|_______|
+ * | | | | | |
+ * 1 | 1 | 2 | 3 | 4 | 5 |
+ * ___|_______|_______|_______|_______|_______|
+ * | | | | | |
+ * 2 | | | | | |
+ * ___|_______|_______|_______|_______|_______|
+ * | | | | | |
+ * 3 | | A | | B | |
+ * ___|_______|_______|_______|_______|_______|
+ * | | | | | |
+ * 4 | | | | | Z |
+ * ___|_______|_______|_______|_______|_______|
+ * | | | | | |
+ * 5 | 1,400 | | 250 | | |
+ * ___|_______|_______|_______|_______|_______|
+ *
+ * </pre>
+ *
+ * Then, the resulting CSV file will contain the following lines (records);
+ * <pre>
+ * 1,2,3,4,5
+ * ,,,,
+ * ,A,,B,
+ * ,,,,Z
+ * "1,400",,250,,
+ * </pre><p>
+ * Typically, the comma is used to separate each of the fields that, together,
+ * constitute a single record or line within the CSV file. This is not however
+ * a hard and fast rule and so this class allows the user to determine which
+ * character is used as the field separator and assumes the comma if none other
+ * is specified.
+ * </p><p>
+ * If a field contains the separator then it will be escaped. If the file should
+ * obey Excel's CSV formatting rules, then the field will be surrounded with
+ * speech marks whilst if it should obey UNIX conventions, each occurrence of
+ * the separator will be preceded by the backslash character.
+ * </p><p>
+ * If a field contains an end of line (EOL) character then it too will be
+ * escaped. If the file should obey Excel's CSV formatting rules then the field
+ * will again be surrounded by speech marks. On the other hand, if the file
+ * should follow UNIX conventions then a single backslash will precede the
+ * EOL character. There is no single applicable standard for UNIX and some
+ * applications replace the CR with \r and the LF with \n but this class will
+ * not do so.
+ * </p><p>
+ * If the field contains double quotes then that character will be escaped. It
+ * seems as though UNIX does not define a standard for this whilst Excel does.
+ * Should the CSV file have to obey Excel's formatting rules then the speech
+ * mark character will be escaped with a second set of speech marks. Finally, an
+ * enclosing set of speech marks will also surround the entire field. Thus, if
+ * the following line of text appeared in a cell - "Hello" he said - it would
+ * look like this when converted into a field within a CSV file - """Hello"" he
+ * said".
+ * </p><p>
+ * Finally, it is worth noting that talk of CSV 'standards' is really slightly
+ * misleading as there is no such thing. It may well be that the code in this
+ * class has to be modified to produce files to suit a specific application
+ * or requirement.
+ * </p>
+ * @author Mark B
+ * @version 1.00 9th April 2010
+ * 1.10 13th April 2010 - Added support for processing all Excel
+ * workbooks in a folder along with the ability
+ * to specify a field separator character.
+ * 2.00 14th April 2010 - Added support for embedded characters; the
+ * field separator, EOL and double quotes or
+ * speech marks. In addition, gave the client
+ * the ability to select how these are handled,
+ * either obeying Excel's or UNIX formatting
+ * conventions.
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public class ToCSV {
+
+ private Workbook workbook;
+ private ArrayList<ArrayList<String>> csvData;
+ private int maxRowWidth;
+ private int formattingConvention;
+ private DataFormatter formatter;
+ private FormulaEvaluator evaluator;
+ private String separator;
+
+ private static final String CSV_FILE_EXTENSION = ".csv";
+ private static final String DEFAULT_SEPARATOR = ",";
+
+ /**
+ * Identifies that the CSV file should obey Excel's formatting conventions
+ * with regard to escaping certain embedded characters - the field separator,
+ * speech mark and end of line (EOL) character
+ */
+ public static final int EXCEL_STYLE_ESCAPING = 0;
+
+ /**
+ * Identifies that the CSV file should obey UNIX formatting conventions
+ * with regard to escaping certain embedded characters - the field separator
+ * and end of line (EOL) character
+ */
+ public static final int UNIX_STYLE_ESCAPING = 1;
+
+ /**
+ * Process the contents of a folder, convert the contents of each Excel
+ * workbook into CSV format and save the resulting file to the specified
+ * folder using the same name as the original workbook with the .xls or
+ * .xlsx extension replaced by .csv. This method will ensure that the
+ * CSV file created contains the comma field separator and that embedded
+ * characters such as the field separator, the EOL and double quotes are
+ * escaped in accordance with Excel's convention.
+ *
+ * @param strSource An instance of the String class that encapsulates the
+ * name of and path to either a folder containing those Excel
+ * workbook(s) or the name of and path to an individual Excel workbook
+ * that is/are to be converted.
+ * @param strDestination An instance of the String class encapsulating the
+ * name of and path to a folder that will contain the resulting CSV
+ * files.
+ * @throws java.io.FileNotFoundException Thrown if any file cannot be located
+ * on the filesystem during processing.
+ * @throws java.io.IOException Thrown if the filesystem encounters any
+ * problems during processing.
+ * @throws java.lang.IllegalArgumentException Thrown if the values passed
+ * to the strSource parameter refers to a file or folder that does not
+ * exist or if the value passed to the strDestination paramater refers
+ * to a folder that does not exist or simply does not refer to a
+ * folder.
+ */
+ public void convertExcelToCSV(String strSource, String strDestination)
+ throws FileNotFoundException, IOException, IllegalArgumentException {
+
+ // Simply chain the call to the overloaded convertExcelToCSV(String,
+ // String, String, int) method, pass the default separator and ensure
+ // that certain embedded characters are escaped in accordance with
+ // Excel's formatting conventions
+ this.convertExcelToCSV(strSource, strDestination,
+ ToCSV.DEFAULT_SEPARATOR, ToCSV.EXCEL_STYLE_ESCAPING);
+ }
+
+ /**
+ * Process the contents of a folder, convert the contents of each Excel
+ * workbook into CSV format and save the resulting file to the specified
+ * folder using the same name as the original workbook with the .xls or
+ * .xlsx extension replaced by .csv. This method allows the client to
+ * define the field separator but will ensure that embedded characters such
+ * as the field separator, the EOL and double quotes are escaped in
+ * accordance with Excel's convention.
+ *
+ * @param strSource An instance of the String class that encapsulates the
+ * name of and path to either a folder containing those Excel
+ * workbook(s) or the name of and path to an individual Excel workbook
+ * that is/are to be converted.
+ * @param strDestination An instance of the String class encapsulating the
+ * name of and path to a folder that will contain the resulting CSV
+ * files.
+ * @param separator An instance of the String class that encapsulates the
+ * character or characters the client wishes to use as the field
+ * separator.
+ * @throws java.io.FileNotFoundException Thrown if any file cannot be located
+ * on the filesystem during processing.
+ * @throws java.io.IOException Thrown if the filesystem encounters any
+ * problems during processing.
+ * @throws java.lang.IllegalArgumentException Thrown if the values passed
+ * to the strSource parameter refers to a file or folder that does not
+ * exist or if the value passed to the strDestination paramater refers
+ * to a folder that does not exist or simply does not refer to a
+ * folder.
+ */
+ public void convertExcelToCSV(String strSource, String strDestination,
+ String separator)
+ throws FileNotFoundException, IOException,
+ IllegalArgumentException {
+
+ // Simply chain the call to the overloaded convertExcelToCSV(String,
+ // String, String, int) method and ensure that certain embedded
+ // characters are escaped in accordance with Excel's formatting
+ // conventions
+ this.convertExcelToCSV(strSource, strDestination,
+ separator, ToCSV.EXCEL_STYLE_ESCAPING);
+ }
+
+ /**
+ * Process the contents of a folder, convert the contents of each Excel
+ * workbook into CSV format and save the resulting file to the specified
+ * folder using the same name as the original workbook with the .xls or
+ * .xlsx extension replaced by .csv
+ *
+ * @param strSource An instance of the String class that encapsulates the
+ * name of and path to either a folder containing those Excel
+ * workbook(s) or the name of and path to an individual Excel workbook
+ * that is/are to be converted.
+ * @param strDestination An instance of the String class encapsulating the name
+ * of and path to a folder that will contain the resulting CSV files.
+ * @param formattingConvention A primitive int whose value will determine
+ * whether certain embedded characters should be escaped in accordance
+ * with Excel's or UNIX formatting conventions. Two constants are
+ * defined to support this option; ToCSV.EXCEL_STYLE_ESCAPING and
+ * ToCSV.UNIX_STYLE_ESCAPING
+ * @param separator An instance of the String class encapsulating the
+ * characters or characters that should be used to separate items
+ * on a line within the CSV file.
+ * @throws java.io.FileNotFoundException Thrown if any file cannot be located
+ * on the filesystem during processing.
+ * @throws java.io.IOException Thrown if the filesystem encounters any
+ * problems during processing.
+ * @throws java.lang.IllegalArgumentException Thrown if the values passed
+ * to the strSource parameter refers to a file or folder that does not
+ * exist, if the value passed to the strDestination paramater refers
+ * to a folder that does not exist, if the value passed to the
+ * strDestination parameter does not refer to a folder or if the
+ * value passed to the formattingConvention parameter is other than
+ * one of the values defined by the constants ToCSV.EXCEL_STYLE_ESCAPING
+ * and ToCSV.UNIX_STYLE_ESCAPING.
+ */
+ public void convertExcelToCSV(String strSource, String strDestination,
+ String separator, int formattingConvention)
+ throws FileNotFoundException, IOException,
+ IllegalArgumentException {
+ // Check that the source file/folder exists.
+ File source = new File(strSource);
+ if(!source.exists()) {
+ throw new IllegalArgumentException("The source for the Excel " +
+ "file(s) cannot be found at " + source);
+ }
+
+ // Ensure thaat the folder the user has chosen to save the CSV files
+ // away into firstly exists and secondly is a folder rather than, for
+ // instance, a data file.
+ File destination = new File(strDestination);
+ if(!destination.exists()) {
+ throw new IllegalArgumentException("The destination directory " + destination + " for the " +
+ "converted CSV file(s) does not exist.");
+ }
+ if(!destination.isDirectory()) {
+ throw new IllegalArgumentException("The destination " + destination + " for the CSV " +
+ "file(s) is not a directory/folder.");
+ }
+
+ // Ensure the value passed to the formattingConvention parameter is
+ // within range.
+ if(formattingConvention != ToCSV.EXCEL_STYLE_ESCAPING &&
+ formattingConvention != ToCSV.UNIX_STYLE_ESCAPING) {
+ throw new IllegalArgumentException("The value passed to the " +
+ "formattingConvention parameter is out of range: " + formattingConvention + ", expecting one of " +
+ ToCSV.EXCEL_STYLE_ESCAPING + " or " + ToCSV.UNIX_STYLE_ESCAPING);
+ }
+
+ // Copy the spearator character and formatting convention into local
+ // variables for use in other methods.
+ this.separator = separator;
+ this.formattingConvention = formattingConvention;
+
+ // Check to see if the sourceFolder variable holds a reference to
+ // a file or a folder full of files.
+ final File[] filesList;
+ if(source.isDirectory()) {
+ // Get a list of all of the Excel spreadsheet files (workbooks) in
+ // the source folder/directory
+ filesList = source.listFiles(new ExcelFilenameFilter());
+ }
+ else {
+ // Assume that it must be a file handle - although there are other
+ // options the code should perhaps check - and store the reference
+ // into the filesList variable.
+ filesList = new File[]{source};
+ }
+
+ // Step through each of the files in the source folder and for each
+ // open the workbook, convert it's contents to CSV format and then
+ // save the resulting file away into the folder specified by the
+ // contents of the destination variable. Note that the name of the
+ // csv file will be created by taking the name of the Excel file,
+ // removing the extension and replacing it with .csv. Note that there
+ // is one drawback with this approach; if the folder holding the files
+ // contains two workbooks whose names match but one is a binary file
+ // (.xls) and the other a SpreadsheetML file (.xlsx), then the names
+ // for both CSV files will be identical and one CSV file will,
+ // therefore, over-write the other.
+ if (filesList != null) {
+ for(File excelFile : filesList) {
+ // Open the workbook
+ this.openWorkbook(excelFile);
+
+ // Convert it's contents into a CSV file
+ this.convertToCSV();
+
+ // Build the name of the csv folder from that of the Excel workbook.
+ // Simply replace the .xls or .xlsx file extension with .csv
+ String destinationFilename = excelFile.getName();
+ destinationFilename = destinationFilename.substring(
+ 0, destinationFilename.lastIndexOf('.')) +
+ ToCSV.CSV_FILE_EXTENSION;
+
+ // Save the CSV file away using the newly constricted file name
+ // and to the specified directory.
+ this.saveCSVFile(new File(destination, destinationFilename));
+ }
+ }
+ }
+
+ /**
+ * Open an Excel workbook ready for conversion.
+ *
+ * @param file An instance of the File class that encapsulates a handle
+ * to a valid Excel workbook. Note that the workbook can be in
+ * either binary (.xls) or SpreadsheetML (.xlsx) format.
+ * @throws java.io.FileNotFoundException Thrown if the file cannot be located.
+ * @throws java.io.IOException Thrown if a problem occurs in the file system.
+ */
+ private void openWorkbook(File file) throws FileNotFoundException, IOException {
+ System.out.println("Opening workbook [" + file.getName() + "]");
+ try (FileInputStream fis = new FileInputStream(file)) {
+
+ // Open the workbook and then create the FormulaEvaluator and
+ // DataFormatter instances that will be needed to, respectively,
+ // force evaluation of forumlae found in cells and create a
+ // formatted String encapsulating the cells contents.
+ this.workbook = WorkbookFactory.create(fis);
+ this.evaluator = this.workbook.getCreationHelper().createFormulaEvaluator();
+ this.formatter = new DataFormatter(true);
+ }
+ }
+
+ /**
+ * Called to convert the contents of the currently opened workbook into
+ * a CSV file.
+ */
+ private void convertToCSV() {
+ Sheet sheet;
+ Row row;
+ int lastRowNum;
+ this.csvData = new ArrayList<>();
+
+ System.out.println("Converting files contents to CSV format.");
+
+ // Discover how many sheets there are in the workbook....
+ int numSheets = this.workbook.getNumberOfSheets();
+
+ // and then iterate through them.
+ for(int i = 0; i < numSheets; i++) {
+
+ // Get a reference to a sheet and check to see if it contains
+ // any rows.
+ sheet = this.workbook.getSheetAt(i);
+ if(sheet.getPhysicalNumberOfRows() > 0) {
+ // Note down the index number of the bottom-most row and
+ // then iterate through all of the rows on the sheet starting
+ // from the very first row - number 1 - even if it is missing.
+ // Recover a reference to the row and then call another method
+ // which will strip the data from the cells and build lines
+ // for inclusion in the resylting CSV file.
+ lastRowNum = sheet.getLastRowNum();
+ for(int j = 0; j <= lastRowNum; j++) {
+ row = sheet.getRow(j);
+ this.rowToCSV(row);
+ }
+ }
+ }
+ }
+
+ /**
+ * Called to actually save the data recovered from the Excel workbook
+ * as a CSV file.
+ *
+ * @param file An instance of the File class that encapsulates a handle
+ * referring to the CSV file.
+ * @throws java.io.FileNotFoundException Thrown if the file cannot be found.
+ * @throws java.io.IOException Thrown to indicate and error occurred in the
+ * underylying file system.
+ */
+ private void saveCSVFile(File file) throws FileNotFoundException, IOException {
+ ArrayList<String> line;
+ StringBuilder buffer;
+ String csvLineElement;
+
+ // Open a writer onto the CSV file.
+ try (BufferedWriter bw = Files.newBufferedWriter(file.toPath(), StandardCharsets.ISO_8859_1)) {
+
+ System.out.println("Saving the CSV file [" + file.getName() + "]");
+
+ // Step through the elements of the ArrayList that was used to hold
+ // all of the data recovered from the Excel workbooks' sheets, rows
+ // and cells.
+ for(int i = 0; i < this.csvData.size(); i++) {
+ buffer = new StringBuilder();
+
+ // Get an element from the ArrayList that contains the data for
+ // the workbook. This element will itself be an ArrayList
+ // containing Strings and each String will hold the data recovered
+ // from a single cell. The for() loop is used to recover elements
+ // from this 'row' ArrayList one at a time and to write the Strings
+ // away to a StringBuilder thus assembling a single line for inclusion
+ // in the CSV file. If a row was empty or if it was short, then
+ // the ArrayList that contains it's data will also be shorter than
+ // some of the others. Therefore, it is necessary to check within
+ // the for loop to ensure that the ArrayList contains data to be
+ // processed. If it does, then an element will be recovered and
+ // appended to the StringBuilder.
+ line = this.csvData.get(i);
+ for(int j = 0; j < this.maxRowWidth; j++) {
+ if(line.size() > j) {
+ csvLineElement = line.get(j);
+ if(csvLineElement != null) {
+ buffer.append(this.escapeEmbeddedCharacters(
+ csvLineElement));
+ }
+ }
+ if(j < (this.maxRowWidth - 1)) {
+ buffer.append(this.separator);
+ }
+ }
+
+ // Once the line is built, write it away to the CSV file.
+ bw.write(buffer.toString().trim());
+
+ // Condition the inclusion of new line characters so as to
+ // avoid an additional, superfluous, new line at the end of
+ // the file.
+ if(i < (this.csvData.size() - 1)) {
+ bw.newLine();
+ }
+ }
+ }
+ }
+
+ /**
+ * Called to convert a row of cells into a line of data that can later be
+ * output to the CSV file.
+ *
+ * @param row An instance of either the HSSFRow or XSSFRow classes that
+ * encapsulates information about a row of cells recovered from
+ * an Excel workbook.
+ */
+ private void rowToCSV(Row row) {
+ Cell cell;
+ int lastCellNum;
+ ArrayList<String> csvLine = new ArrayList<>();
+
+ // Check to ensure that a row was recovered from the sheet as it is
+ // possible that one or more rows between other populated rows could be
+ // missing - blank. If the row does contain cells then...
+ if(row != null) {
+
+ // Get the index for the right most cell on the row and then
+ // step along the row from left to right recovering the contents
+ // of each cell, converting that into a formatted String and
+ // then storing the String into the csvLine ArrayList.
+ lastCellNum = row.getLastCellNum();
+ for(int i = 0; i <= lastCellNum; i++) {
+ cell = row.getCell(i);
+ if(cell == null) {
+ csvLine.add("");
+ }
+ else {
+ if(cell.getCellType() != CellType.FORMULA) {
+ csvLine.add(this.formatter.formatCellValue(cell));
+ }
+ else {
+ csvLine.add(this.formatter.formatCellValue(cell, this.evaluator));
+ }
+ }
+ }
+ // Make a note of the index number of the right most cell. This value
+ // will later be used to ensure that the matrix of data in the CSV file
+ // is square.
+ if(lastCellNum > this.maxRowWidth) {
+ this.maxRowWidth = lastCellNum;
+ }
+ }
+ this.csvData.add(csvLine);
+ }
+
+ /**
+ * Checks to see whether the field - which consists of the formatted
+ * contents of an Excel worksheet cell encapsulated within a String - contains
+ * any embedded characters that must be escaped. The method is able to
+ * comply with either Excel's or UNIX formatting conventions in the
+ * following manner;
+ *
+ * With regard to UNIX conventions, if the field contains any embedded
+ * field separator or EOL characters they will each be escaped by prefixing
+ * a leading backspace character. These are the only changes that have yet
+ * emerged following some research as being required.
+ *
+ * Excel has other embedded character escaping requirements, some that emerged
+ * from empirical testing, other through research. Firstly, with regards to
+ * any embedded speech marks ("), each occurrence should be escaped with
+ * another speech mark and the whole field then surrounded with speech marks.
+ * Thus if a field holds <em>"Hello" he said</em> then it should be modified
+ * to appear as <em>"""Hello"" he said"</em>. Furthermore, if the field
+ * contains either embedded separator or EOL characters, it should also
+ * be surrounded with speech marks. As a result <em>1,400</em> would become
+ * <em>"1,400"</em> assuming that the comma is the required field separator.
+ * This has one consequence in, if a field contains embedded speech marks
+ * and embedded separator characters, checks for both are not required as the
+ * additional set of speech marks that should be placed around ay field
+ * containing embedded speech marks will also account for the embedded
+ * separator.
+ *
+ * It is worth making one further note with regard to embedded EOL
+ * characters. If the data in a worksheet is exported as a CSV file using
+ * Excel itself, then the field will be surounded with speech marks. If the
+ * resulting CSV file is then re-imports into another worksheet, the EOL
+ * character will result in the original simgle field occupying more than
+ * one cell. This same 'feature' is replicated in this classes behaviour.
+ *
+ * @param field An instance of the String class encapsulating the formatted
+ * contents of a cell on an Excel worksheet.
+ * @return A String that encapsulates the formatted contents of that
+ * Excel worksheet cell but with any embedded separator, EOL or
+ * speech mark characters correctly escaped.
+ */
+ private String escapeEmbeddedCharacters(String field) {
+ StringBuilder buffer;
+
+ // If the fields contents should be formatted to confrom with Excel's
+ // convention....
+ if(this.formattingConvention == ToCSV.EXCEL_STYLE_ESCAPING) {
+
+ // Firstly, check if there are any speech marks (") in the field;
+ // each occurrence must be escaped with another set of spech marks
+ // and then the entire field should be enclosed within another
+ // set of speech marks. Thus, "Yes" he said would become
+ // """Yes"" he said"
+ if(field.contains("\"")) {
+ buffer = new StringBuilder(field.replaceAll("\"", "\\\"\\\""));
+ buffer.insert(0, "\"");
+ buffer.append("\"");
+ }
+ else {
+ // If the field contains either embedded separator or EOL
+ // characters, then escape the whole field by surrounding it
+ // with speech marks.
+ buffer = new StringBuilder(field);
+ if((buffer.indexOf(this.separator)) > -1 ||
+ (buffer.indexOf("\n")) > -1) {
+ buffer.insert(0, "\"");
+ buffer.append("\"");
+ }
+ }
+ return(buffer.toString().trim());
+ }
+ // The only other formatting convention this class obeys is the UNIX one
+ // where any occurrence of the field separator or EOL character will
+ // be escaped by preceding it with a backslash.
+ else {
+ if(field.contains(this.separator)) {
+ field = field.replaceAll(this.separator, ("\\\\" + this.separator));
+ }
+ if(field.contains("\n")) {
+ field = field.replaceAll("\n", "\\\\\n");
+ }
+ return(field);
+ }
+ }
+
+ /**
+ * The main() method contains code that demonstrates how to use the class.
+ *
+ * @param args An array containing zero, one or more elements all of type
+ * String. Each element will encapsulate an argument specified by the
+ * user when running the program from the command prompt.
+ */
+ public static void main(String[] args) {
+ // Check the number of arguments passed to the main method. There
+ // must be two, three or four; the name of and path to either the folder
+ // containing the Excel files or an individual Excel workbook that is/are
+ // to be converted, the name of and path to the folder to which the CSV
+ // files should be written, - optionally - the separator character
+ // that should be used to separate individual items (fields) on the
+ // lines (records) of the CSV file and - again optionally - an integer
+ // that idicates whether the CSV file ought to obey Excel's or UNIX
+ // convnetions with regard to formatting fields that contain embedded
+ // separator, Speech mark or EOL character(s).
+ //
+ // Note that the names of the CSV files will be derived from those
+ // of the Excel file(s). Put simply the .xls or .xlsx extension will be
+ // replaced with .csv. Therefore, if the source folder contains files
+ // with matching names but different extensions - Test.xls and Test.xlsx
+ // for example - then the CSV file generated from one will overwrite
+ // that generated from the other.
+ ToCSV converter;
+ boolean converted = true;
+ long startTime = System.currentTimeMillis();
+ try {
+ converter = new ToCSV();
+ if(args.length == 2) {
+ // Just the Source File/Folder and Destination Folder were
+ // passed to the main method.
+ converter.convertExcelToCSV(args[0], args[1]);
+ }
+ else if(args.length == 3) {
+ // The Source File/Folder, Destination Folder and Separator
+ // were passed to the main method.
+ converter.convertExcelToCSV(args[0], args[1], args[2]);
+ }
+ else if(args.length == 4) {
+ // The Source File/Folder, Destination Folder, Separator and
+ // Formatting Convention were passed to the main method.
+ converter.convertExcelToCSV(args[0], args[1],
+ args[2], Integer.parseInt(args[3]));
+ }
+ else {
+ // None or more than four parameters were passed so display
+ //a Usage message.
+ System.out.println("Usage: java ToCSV [Source File/Folder] " +
+ "[Destination Folder] [Separator] [Formatting Convention]\n" +
+ "\tSource File/Folder\tThis argument should contain the name of and\n" +
+ "\t\t\t\tpath to either a single Excel workbook or a\n" +
+ "\t\t\t\tfolder containing one or more Excel workbooks.\n" +
+ "\tDestination Folder\tThe name of and path to the folder that the\n" +
+ "\t\t\t\tCSV files should be written out into. The\n" +
+ "\t\t\t\tfolder must exist before running the ToCSV\n" +
+ "\t\t\t\tcode as it will not check for or create it.\n" +
+ "\tSeparator\t\tOptional. The character or characters that\n" +
+ "\t\t\t\tshould be used to separate fields in the CSV\n" +
+ "\t\t\t\trecord. If no value is passed then the comma\n" +
+ "\t\t\t\twill be assumed.\n" +
+ "\tFormatting Convention\tOptional. This argument can take one of two\n" +
+ "\t\t\t\tvalues. Passing 0 (zero) will result in a CSV\n" +
+ "\t\t\t\tfile that obeys Excel's formatting conventions\n" +
+ "\t\t\t\twhilst passing 1 (one) will result in a file\n" +
+ "\t\t\t\tthat obeys UNIX formatting conventions. If no\n" +
+ "\t\t\t\tvalue is passed, then the CSV file produced\n" +
+ "\t\t\t\twill obey Excel's formatting conventions.");
+ converted = false;
+ }
+ }
+ // It is not wise to have such a wide catch clause - Exception is very
+ // close to being at the top of the inheritance hierarchy - though it
+ // will suffice for this example as it is really not possible to recover
+ // easilly from an exceptional set of circumstances at this point in the
+ // program. It should however, ideally be replaced with one or more
+ // catch clauses optimised to handle more specific problems.
+ catch(Exception ex) {
+ System.out.println("Caught an: " + ex.getClass().getName());
+ System.out.println("Message: " + ex.getMessage());
+ System.out.println("Stacktrace follows:.....");
+ ex.printStackTrace(System.out);
+ converted = false;
+ }
+
+ if (converted) {
+ System.out.println("Conversion took " +
+ ((System.currentTimeMillis() - startTime)/1000) + " seconds");
+ }
+ }
+
+ /**
+ * An instance of this class can be used to control the files returned
+ * be a call to the listFiles() method when made on an instance of the
+ * File class and that object refers to a folder/directory
+ */
+ static class ExcelFilenameFilter implements FilenameFilter {
+
+ /**
+ * Determine those files that will be returned by a call to the
+ * listFiles() method. In this case, the name of the file must end with
+ * either of the following two extension; '.xls' or '.xlsx'. For the
+ * future, it is very possible to parameterise this and allow the
+ * containing class to pass, for example, an array of Strings to this
+ * class on instantiation. Each element in that array could encapsulate
+ * a valid file extension - '.xls', '.xlsx', '.xlt', '.xlst', etc. These
+ * could then be used to control which files were returned by the call
+ * to the listFiles() method.
+ *
+ * @param file An instance of the File class that encapsulates a handle
+ * referring to the folder/directory that contains the file.
+ * @param name An instance of the String class that encapsulates the
+ * name of the file.
+ * @return A boolean value that indicates whether the file should be
+ * included in the array retirned by the call to the listFiles()
+ * method. In this case true will be returned if the name of the
+ * file ends with either '.xls' or '.xlsx' and false will be
+ * returned in all other instances.
+ */
+ @Override
+ public boolean accept(File file, String name) {
+ return(name.endsWith(".xls") || name.endsWith(".xlsx"));
+ }
+ }
+} \ No newline at end of file
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/ss/formula/CalculateMortgage.java b/poi-examples/src/main/java/org/apache/poi/examples/ss/formula/CalculateMortgage.java
new file mode 100644
index 0000000000..2675df181b
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/ss/formula/CalculateMortgage.java
@@ -0,0 +1,91 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.ss.formula;
+
+import org.apache.poi.ss.formula.OperationEvaluationContext;
+import org.apache.poi.ss.formula.eval.ErrorEval;
+import org.apache.poi.ss.formula.eval.EvaluationException;
+import org.apache.poi.ss.formula.eval.NumberEval;
+import org.apache.poi.ss.formula.eval.OperandResolver;
+import org.apache.poi.ss.formula.eval.ValueEval;
+import org.apache.poi.ss.formula.functions.FreeRefFunction;
+
+/**
+ * A simple user-defined function to calculate principal and interest.
+ *
+ * @author Jon Svede ( jon [at] loquatic [dot] com )
+ * @author Brian Bush ( brian [dot] bush [at] nrel [dot] gov )
+ *
+ */
+public class CalculateMortgage implements FreeRefFunction {
+
+ @Override
+ public ValueEval evaluate( ValueEval[] args, OperationEvaluationContext ec ) {
+
+ // verify that we have enough data
+ if (args.length != 3) {
+ return ErrorEval.VALUE_INVALID;
+ }
+
+ // declare doubles for values
+ double principal, rate, years, result;
+ try {
+ // extract values as ValueEval
+ ValueEval v1 = OperandResolver.getSingleValue( args[0],
+ ec.getRowIndex(),
+ ec.getColumnIndex() ) ;
+ ValueEval v2 = OperandResolver.getSingleValue( args[1],
+ ec.getRowIndex(),
+ ec.getColumnIndex() ) ;
+ ValueEval v3 = OperandResolver.getSingleValue( args[2],
+ ec.getRowIndex(),
+ ec.getColumnIndex() ) ;
+
+ // get data as doubles
+ principal = OperandResolver.coerceValueToDouble( v1 ) ;
+ rate = OperandResolver.coerceValueToDouble( v2 ) ;
+ years = OperandResolver.coerceValueToDouble( v3 ) ;
+
+ result = calculateMortgagePayment( principal, rate, years ) ;
+ System.out.println( "Result = " + result ) ;
+
+ checkValue(result);
+
+ } catch (EvaluationException e) {
+ return e.getErrorEval();
+ }
+
+ return new NumberEval( result ) ;
+ }
+
+ public double calculateMortgagePayment( double p, double r, double y ) {
+ double i = r / 12 ;
+ double n = y * 12 ;
+
+ return p * (( i * Math.pow((1 + i),n ) ) / ( Math.pow((1 + i),n) - 1));
+ }
+ /**
+ * Excel does not support infinities and NaNs, rather, it gives a #NUM! error in these cases
+ *
+ * @throws EvaluationException (#NUM!) if <tt>result</tt> is <tt>NaN</> or <tt>Infinity</tt>
+ */
+ private void checkValue(double result) throws EvaluationException {
+ if (Double.isNaN(result) || Double.isInfinite(result)) {
+ throw new EvaluationException(ErrorEval.NUM_ERROR);
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/ss/formula/CheckFunctionsSupported.java b/poi-examples/src/main/java/org/apache/poi/examples/ss/formula/CheckFunctionsSupported.java
new file mode 100644
index 0000000000..4135c80904
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/ss/formula/CheckFunctionsSupported.java
@@ -0,0 +1,162 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.ss.formula;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.poi.ss.formula.eval.NotImplementedException;
+import org.apache.poi.ss.formula.eval.NotImplementedFunctionException;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.FormulaEvaluator;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.usermodel.WorkbookFactory;
+import org.apache.poi.ss.util.CellReference;
+
+/**
+ * Attempts to re-evaluate all the formulas in the workbook, and
+ * reports what (if any) formula functions used are not (currently)
+ * supported by Apache POI.
+ *
+ * <p>This provides examples of how to evaluate formulas in excel
+ * files using Apache POI, along with how to handle errors whilst
+ * doing so.
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public class CheckFunctionsSupported {
+ public static void main(String[] args) throws Exception {
+ if (args.length < 1) {
+ System.err.println("Use:");
+ System.err.println(" CheckFunctionsSupported <filename>");
+ return;
+ }
+
+ Workbook wb = WorkbookFactory.create(new File(args[0]));
+ CheckFunctionsSupported check = new CheckFunctionsSupported(wb);
+
+ // Fetch all the problems
+ List<FormulaEvaluationProblems> problems = new ArrayList<>();
+ for (int sn=0; sn<wb.getNumberOfSheets(); sn++) {
+ problems.add(check.getEvaluationProblems(sn));
+ }
+
+ // Produce an overall summary
+ Set<String> unsupportedFunctions = new TreeSet<>();
+ for (FormulaEvaluationProblems p : problems) {
+ unsupportedFunctions.addAll(p.unsupportedFunctions);
+ }
+ if (unsupportedFunctions.isEmpty()) {
+ System.out.println("There are no unsupported formula functions used");
+ } else {
+ System.out.println("Unsupported formula functions:");
+ for (String function : unsupportedFunctions) {
+ System.out.println(" " + function);
+ }
+ System.out.println("Total unsupported functions = " + unsupportedFunctions.size());
+ }
+
+ // Report sheet by sheet
+ for (int sn=0; sn<wb.getNumberOfSheets(); sn++) {
+ String sheetName = wb.getSheetName(sn);
+ FormulaEvaluationProblems probs = problems.get(sn);
+
+ System.out.println();
+ System.out.println("Sheet = " + sheetName);
+
+ if (probs.unevaluatableCells.isEmpty()) {
+ System.out.println(" All cells evaluated without error");
+ } else {
+ for (CellReference cr : probs.unevaluatableCells.keySet()) {
+ System.out.println(" " + cr.formatAsString() + " - " +
+ probs.unevaluatableCells.get(cr));
+ }
+ }
+ }
+ }
+
+ private final Workbook workbook;
+ private final FormulaEvaluator evaluator;
+ public CheckFunctionsSupported(Workbook workbook) {
+ this.workbook = workbook;
+ this.evaluator = workbook.getCreationHelper().createFormulaEvaluator();
+ }
+
+ public Set<String> getUnsupportedFunctions(String sheetName) {
+ return getUnsupportedFunctions(workbook.getSheet(sheetName));
+ }
+ public Set<String> getUnsupportedFunctions(int sheetIndex) {
+ return getUnsupportedFunctions(workbook.getSheetAt(sheetIndex));
+ }
+ public Set<String> getUnsupportedFunctions(Sheet sheet) {
+ FormulaEvaluationProblems problems = getEvaluationProblems(sheet);
+ return problems.unsupportedFunctions;
+ }
+
+ public FormulaEvaluationProblems getEvaluationProblems(String sheetName) {
+ return getEvaluationProblems(workbook.getSheet(sheetName));
+ }
+ public FormulaEvaluationProblems getEvaluationProblems(int sheetIndex) {
+ return getEvaluationProblems(workbook.getSheetAt(sheetIndex));
+ }
+ public FormulaEvaluationProblems getEvaluationProblems(Sheet sheet) {
+ Set<String> unsupportedFunctions = new HashSet<>();
+ Map<CellReference,Exception> unevaluatableCells = new HashMap<>();
+
+ for (Row r : sheet) {
+ for (Cell c : r) {
+ try {
+ evaluator.evaluate(c);
+ } catch (Exception e) {
+ if (e instanceof NotImplementedException && e.getCause() != null) {
+ // Has been wrapped with cell details, but we know those
+ e = (Exception)e.getCause();
+ }
+
+ if (e instanceof NotImplementedFunctionException) {
+ NotImplementedFunctionException nie = (NotImplementedFunctionException)e;
+ unsupportedFunctions.add(nie.getFunctionName());
+ }
+ unevaluatableCells.put(new CellReference(c), e);
+ }
+ }
+ }
+
+ return new FormulaEvaluationProblems(unsupportedFunctions, unevaluatableCells);
+ }
+
+ public static class FormulaEvaluationProblems {
+ /** Which used functions are unsupported by POI at this time */
+ private final Set<String> unsupportedFunctions;
+ /** Which cells had unevaluatable formulas, and why? */
+ private final Map<CellReference,Exception> unevaluatableCells;
+
+ protected FormulaEvaluationProblems(Set<String> unsupportedFunctions,
+ Map<CellReference, Exception> unevaluatableCells) {
+ this.unsupportedFunctions = Collections.unmodifiableSet(unsupportedFunctions);
+ this.unevaluatableCells = Collections.unmodifiableMap(unevaluatableCells);
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/ss/formula/SettingExternalFunction.java b/poi-examples/src/main/java/org/apache/poi/examples/ss/formula/SettingExternalFunction.java
new file mode 100644
index 0000000000..49feb3f7aa
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/ss/formula/SettingExternalFunction.java
@@ -0,0 +1,93 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.ss.formula;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.poi.ss.formula.OperationEvaluationContext;
+import org.apache.poi.ss.formula.eval.ErrorEval;
+import org.apache.poi.ss.formula.eval.ValueEval;
+import org.apache.poi.ss.formula.functions.FreeRefFunction;
+import org.apache.poi.ss.formula.udf.UDFFinder;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Demonstrates how to use functions provided by third-party add-ins, e.g. Bloomberg Excel Add-in.
+ *
+ * There can be situations when you are not interested in formula evaluation,
+ * you just need to set the formula and the workbook will be evaluation by the client.
+ */
+public class SettingExternalFunction {
+
+ /**
+ * wrap external functions in a plugin
+ */
+ public static class BloombergAddIn implements UDFFinder {
+ private final Map<String, FreeRefFunction> _functionsByName;
+
+ public BloombergAddIn() {
+ // dummy function that returns NA
+ // don't care about the implementation, we are not interested in evaluation
+ // and this method will never be called
+ FreeRefFunction NA = new FreeRefFunction() {
+ @Override
+ public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) {
+ return ErrorEval.NA;
+ }
+ };
+ _functionsByName = new HashMap<>();
+ _functionsByName.put("BDP", NA);
+ _functionsByName.put("BDH", NA);
+ _functionsByName.put("BDS", NA);
+ }
+
+ @Override
+ public FreeRefFunction findFunction(String name) {
+ return _functionsByName.get(name.toUpperCase(Locale.ROOT));
+ }
+
+ }
+
+ public static void main( String[] args ) throws IOException {
+
+ try (Workbook wb = new XSSFWorkbook()) { // or new HSSFWorkbook()
+
+ // register the add-in
+ wb.addToolPack(new BloombergAddIn());
+
+ Sheet sheet = wb.createSheet();
+ Row row = sheet.createRow(0);
+ row.createCell(0).setCellFormula("BDP(\"GOOG Equity\",\"CHG_PCT_YTD\")/100");
+ row.createCell(1).setCellFormula("BDH(\"goog us equity\",\"EBIT\",\"1/1/2005\",\"12/31/2009\",\"per=cy\",\"curr=USD\") ");
+ row.createCell(2).setCellFormula("BDS(\"goog us equity\",\"top_20_holders_public_filings\") ");
+
+ try (FileOutputStream out = new FileOutputStream("bloomberg-demo.xlsx")) {
+ wb.write(out);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/ss/formula/UserDefinedFunctionExample.java b/poi-examples/src/main/java/org/apache/poi/examples/ss/formula/UserDefinedFunctionExample.java
new file mode 100644
index 0000000000..939fd9ab9d
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/ss/formula/UserDefinedFunctionExample.java
@@ -0,0 +1,80 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.ss.formula;
+
+import java.io.File;
+
+import org.apache.poi.ss.formula.functions.FreeRefFunction;
+import org.apache.poi.ss.formula.udf.DefaultUDFFinder;
+import org.apache.poi.ss.formula.udf.UDFFinder;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellValue;
+import org.apache.poi.ss.usermodel.FormulaEvaluator;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.usermodel.WorkbookFactory;
+import org.apache.poi.ss.util.CellReference;
+
+
+/**
+ * An example class of how to invoke a User Defined Function for a given
+ * XLS instance using POI's UDFFinder implementation.
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class UserDefinedFunctionExample {
+
+ private UserDefinedFunctionExample() {}
+
+ public static void main(String[] args ) throws Exception {
+
+ if( args.length != 2 ) {
+ // e.g. src/examples/src/org/apache/poi/ss/examples/formula/mortgage-calculation.xls Sheet1!B4
+ System.out.println( "usage: UserDefinedFunctionExample fileName cellId" ) ;
+ return;
+ }
+
+ System.out.println( "fileName: " + args[0] ) ;
+ System.out.println( "cell: " + args[1] ) ;
+
+ File workbookFile = new File( args[0] ) ;
+
+ try (Workbook workbook = WorkbookFactory.create(workbookFile, null, true)) {
+ String[] functionNames = {"calculatePayment"};
+ FreeRefFunction[] functionImpls = {new CalculateMortgage()};
+
+ UDFFinder udfToolpack = new DefaultUDFFinder(functionNames, functionImpls);
+
+ // register the user-defined function in the workbook
+ workbook.addToolPack(udfToolpack);
+
+ FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
+
+ CellReference cr = new CellReference(args[1]);
+ String sheetName = cr.getSheetName();
+ Sheet sheet = workbook.getSheet(sheetName);
+ int rowIdx = cr.getRow();
+ int colIdx = cr.getCol();
+ Row row = sheet.getRow(rowIdx);
+ Cell cell = row.getCell(colIdx);
+
+ CellValue value = evaluator.evaluate(cell);
+
+ System.out.println("returns value: " + value);
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/ss/formula/mortgage-calculation.xls b/poi-examples/src/main/java/org/apache/poi/examples/ss/formula/mortgage-calculation.xls
new file mode 100644
index 0000000000..4e71ba8e65
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/ss/formula/mortgage-calculation.xls
Binary files differ
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/ss/html/HSSFHtmlHelper.java b/poi-examples/src/main/java/org/apache/poi/examples/ss/html/HSSFHtmlHelper.java
new file mode 100644
index 0000000000..4614a31031
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/ss/html/HSSFHtmlHelper.java
@@ -0,0 +1,66 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.ss.html;
+
+import java.util.Formatter;
+
+import org.apache.poi.hssf.usermodel.HSSFCellStyle;
+import org.apache.poi.hssf.usermodel.HSSFPalette;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hssf.util.HSSFColor;
+import org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined;
+import org.apache.poi.ss.usermodel.CellStyle;
+
+/**
+ * Implementation of {@link HtmlHelper} for HSSF files.
+ */
+public class HSSFHtmlHelper implements HtmlHelper {
+ private final HSSFWorkbook wb;
+ private final HSSFPalette colors;
+
+ private static final HSSFColor HSSF_AUTO = HSSFColorPredefined.AUTOMATIC.getColor();
+
+ public HSSFHtmlHelper(HSSFWorkbook wb) {
+ this.wb = wb;
+ // If there is no custom palette, then this creates a new one that is
+ // a copy of the default
+ colors = wb.getCustomPalette();
+ }
+
+ @Override
+ public void colorStyles(CellStyle style, Formatter out) {
+ HSSFCellStyle cs = (HSSFCellStyle) style;
+ out.format(" /* fill pattern = %d */%n", cs.getFillPattern().getCode());
+ styleColor(out, "background-color", cs.getFillForegroundColor());
+ styleColor(out, "color", cs.getFont(wb).getColor());
+ styleColor(out, "border-left-color", cs.getLeftBorderColor());
+ styleColor(out, "border-right-color", cs.getRightBorderColor());
+ styleColor(out, "border-top-color", cs.getTopBorderColor());
+ styleColor(out, "border-bottom-color", cs.getBottomBorderColor());
+ }
+
+ private void styleColor(Formatter out, String attr, short index) {
+ HSSFColor color = colors.getColor(index);
+ if (index == HSSF_AUTO.getIndex() || color == null) {
+ out.format(" /* %s: index = %d */%n", attr, index);
+ } else {
+ short[] rgb = color.getTriplet();
+ out.format(" %s: #%02x%02x%02x; /* index = %d */%n", attr, rgb[0],
+ rgb[1], rgb[2], index);
+ }
+ }
+} \ No newline at end of file
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/ss/html/HtmlHelper.java b/poi-examples/src/main/java/org/apache/poi/examples/ss/html/HtmlHelper.java
new file mode 100644
index 0000000000..8747ad4c9d
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/ss/html/HtmlHelper.java
@@ -0,0 +1,40 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.ss.html;
+
+import java.util.Formatter;
+
+import org.apache.poi.ss.usermodel.CellStyle;
+
+/**
+ * This interface is used where code wants to be independent of the workbook
+ * formats. If you are writing such code, you can add a method to this
+ * interface, and then implement it for both HSSF and XSSF workbooks, letting
+ * the driving code stay independent of format.
+ *
+ * @author Ken Arnold, Industrious Media LLC
+ */
+public interface HtmlHelper {
+ /**
+ * Outputs the appropriate CSS style for the given cell style.
+ *
+ * @param style The cell style.
+ * @param out The place to write the output.
+ */
+ void colorStyles(CellStyle style, Formatter out);
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/ss/html/ToHtml.java b/poi-examples/src/main/java/org/apache/poi/examples/ss/html/ToHtml.java
new file mode 100644
index 0000000000..65c8878916
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/ss/html/ToHtml.java
@@ -0,0 +1,506 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.ss.html;
+
+import java.io.BufferedReader;
+import java.io.Closeable;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+import java.util.Formatter;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.format.CellFormat;
+import org.apache.poi.ss.format.CellFormatResult;
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.VerticalAlignment;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.usermodel.WorkbookFactory;
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * This example shows how to display a spreadsheet in HTML using the classes for
+ * spreadsheet display.
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class ToHtml {
+ private final Workbook wb;
+ private final Appendable output;
+ private boolean completeHTML;
+ private Formatter out;
+ private boolean gotBounds;
+ private int firstColumn;
+ private int endColumn;
+ private HtmlHelper helper;
+
+ private static final String DEFAULTS_CLASS = "excelDefaults";
+ private static final String COL_HEAD_CLASS = "colHeader";
+ private static final String ROW_HEAD_CLASS = "rowHeader";
+
+ private static final Map<HorizontalAlignment, String> HALIGN = mapFor(
+ HorizontalAlignment.LEFT, "left",
+ HorizontalAlignment.CENTER, "center",
+ HorizontalAlignment.RIGHT, "right",
+ HorizontalAlignment.FILL, "left",
+ HorizontalAlignment.JUSTIFY, "left",
+ HorizontalAlignment.CENTER_SELECTION, "center");
+
+ private static final Map<VerticalAlignment, String> VALIGN = mapFor(
+ VerticalAlignment.BOTTOM, "bottom",
+ VerticalAlignment.CENTER, "middle",
+ VerticalAlignment.TOP, "top");
+
+ private static final Map<BorderStyle, String> BORDER = mapFor(
+ BorderStyle.DASH_DOT, "dashed 1pt",
+ BorderStyle.DASH_DOT_DOT, "dashed 1pt",
+ BorderStyle.DASHED, "dashed 1pt",
+ BorderStyle.DOTTED, "dotted 1pt",
+ BorderStyle.DOUBLE, "double 3pt",
+ BorderStyle.HAIR, "solid 1px",
+ BorderStyle.MEDIUM, "solid 2pt",
+ BorderStyle.MEDIUM_DASH_DOT, "dashed 2pt",
+ BorderStyle.MEDIUM_DASH_DOT_DOT, "dashed 2pt",
+ BorderStyle.MEDIUM_DASHED, "dashed 2pt",
+ BorderStyle.NONE, "none",
+ BorderStyle.SLANTED_DASH_DOT, "dashed 2pt",
+ BorderStyle.THICK, "solid 3pt",
+ BorderStyle.THIN, "dashed 1pt");
+
+ private static final int IDX_TABLE_WIDTH = -2;
+ private static final int IDX_HEADER_COL_WIDTH = -1;
+
+
+ @SuppressWarnings({"unchecked"})
+ private static <K, V> Map<K, V> mapFor(Object... mapping) {
+ Map<K, V> map = new HashMap<>();
+ for (int i = 0; i < mapping.length; i += 2) {
+ map.put((K) mapping[i], (V) mapping[i + 1]);
+ }
+ return map;
+ }
+
+ /**
+ * Creates a new examples to HTML for the given workbook.
+ *
+ * @param wb The workbook.
+ * @param output Where the HTML output will be written.
+ *
+ * @return An object for converting the workbook to HTML.
+ */
+ public static ToHtml create(Workbook wb, Appendable output) {
+ return new ToHtml(wb, output);
+ }
+
+ /**
+ * Creates a new examples to HTML for the given workbook. If the path ends
+ * with "<tt>.xlsx</tt>" an {@link XSSFWorkbook} will be used; otherwise
+ * this will use an {@link HSSFWorkbook}.
+ *
+ * @param path The file that has the workbook.
+ * @param output Where the HTML output will be written.
+ *
+ * @return An object for converting the workbook to HTML.
+ */
+ public static ToHtml create(String path, Appendable output)
+ throws IOException {
+ return create(new FileInputStream(path), output);
+ }
+
+ /**
+ * Creates a new examples to HTML for the given workbook. This attempts to
+ * detect whether the input is XML (so it should create an {@link
+ * XSSFWorkbook} or not (so it should create an {@link HSSFWorkbook}).
+ *
+ * @param in The input stream that has the workbook.
+ * @param output Where the HTML output will be written.
+ *
+ * @return An object for converting the workbook to HTML.
+ */
+ public static ToHtml create(InputStream in, Appendable output)
+ throws IOException {
+ Workbook wb = WorkbookFactory.create(in);
+ return create(wb, output);
+ }
+
+ private ToHtml(Workbook wb, Appendable output) {
+ if (wb == null) {
+ throw new NullPointerException("wb");
+ }
+ if (output == null) {
+ throw new NullPointerException("output");
+ }
+ this.wb = wb;
+ this.output = output;
+ setupColorMap();
+ }
+
+ private void setupColorMap() {
+ if (wb instanceof HSSFWorkbook) {
+ helper = new HSSFHtmlHelper((HSSFWorkbook) wb);
+ } else if (wb instanceof XSSFWorkbook) {
+ helper = new XSSFHtmlHelper();
+ } else {
+ throw new IllegalArgumentException(
+ "unknown workbook type: " + wb.getClass().getSimpleName());
+ }
+ }
+
+ /**
+ * Run this class as a program
+ *
+ * @param args The command line arguments.
+ *
+ * @throws Exception Exception we don't recover from.
+ */
+ public static void main(String[] args) throws Exception {
+ if(args.length < 2){
+ System.err.println("usage: ToHtml inputWorkbook outputHtmlFile");
+ return;
+ }
+
+ try (PrintWriter pw = new PrintWriter(args[1], "UTF-8")) {
+ ToHtml toHtml = create(args[0], pw);
+ toHtml.setCompleteHTML(true);
+ toHtml.printPage();
+ }
+ }
+
+ public void setCompleteHTML(boolean completeHTML) {
+ this.completeHTML = completeHTML;
+ }
+
+ public void printPage() throws IOException {
+ try {
+ ensureOut();
+ if (completeHTML) {
+ out.format(
+ "<?xml version=\"1.0\" encoding=\"iso-8859-1\" ?>%n");
+ out.format("<html>%n");
+ out.format("<head>%n");
+ out.format("</head>%n");
+ out.format("<body>%n");
+ }
+
+ print();
+
+ if (completeHTML) {
+ out.format("</body>%n");
+ out.format("</html>%n");
+ }
+ } finally {
+ IOUtils.closeQuietly(out);
+ if (output instanceof Closeable) {
+ IOUtils.closeQuietly((Closeable) output);
+ }
+ }
+ }
+
+ public void print() {
+ printInlineStyle();
+ printSheets();
+ }
+
+ private void printInlineStyle() {
+ //out.format("<link href=\"excelStyle.css\" rel=\"stylesheet\" type=\"text/css\">%n");
+ out.format("<style type=\"text/css\">%n");
+ printStyles();
+ out.format("</style>%n");
+ }
+
+ private void ensureOut() {
+ if (out == null) {
+ out = new Formatter(output, Locale.ROOT);
+ }
+ }
+
+ public void printStyles() {
+ ensureOut();
+
+ // First, copy the base css
+ try (BufferedReader in = new BufferedReader(new InputStreamReader(
+ getClass().getResourceAsStream("excelStyle.css"), StandardCharsets.ISO_8859_1))){
+ String line;
+ while ((line = in.readLine()) != null) {
+ out.format("%s%n", line);
+ }
+ } catch (IOException e) {
+ throw new IllegalStateException("Reading standard css", e);
+ }
+
+ // now add css for each used style
+ Set<CellStyle> seen = new HashSet<>();
+ for (int i = 0; i < wb.getNumberOfSheets(); i++) {
+ Sheet sheet = wb.getSheetAt(i);
+ Iterator<Row> rows = sheet.rowIterator();
+ while (rows.hasNext()) {
+ Row row = rows.next();
+ for (Cell cell : row) {
+ CellStyle style = cell.getCellStyle();
+ if (!seen.contains(style)) {
+ printStyle(style);
+ seen.add(style);
+ }
+ }
+ }
+ }
+ }
+
+ private void printStyle(CellStyle style) {
+ out.format(".%s .%s {%n", DEFAULTS_CLASS, styleName(style));
+ styleContents(style);
+ out.format("}%n");
+ }
+
+ private void styleContents(CellStyle style) {
+ styleOut("text-align", style.getAlignment(), HALIGN);
+ styleOut("vertical-align", style.getVerticalAlignment(), VALIGN);
+ fontStyle(style);
+ borderStyles(style);
+ helper.colorStyles(style, out);
+ }
+
+ private void borderStyles(CellStyle style) {
+ styleOut("border-left", style.getBorderLeft(), BORDER);
+ styleOut("border-right", style.getBorderRight(), BORDER);
+ styleOut("border-top", style.getBorderTop(), BORDER);
+ styleOut("border-bottom", style.getBorderBottom(), BORDER);
+ }
+
+ private void fontStyle(CellStyle style) {
+ Font font = wb.getFontAt(style.getFontIndex());
+
+ if (font.getBold()) {
+ out.format(" font-weight: bold;%n");
+ }
+ if (font.getItalic()) {
+ out.format(" font-style: italic;%n");
+ }
+
+ int fontheight = font.getFontHeightInPoints();
+ if (fontheight == 9) {
+ //fix for stupid ol Windows
+ fontheight = 10;
+ }
+ out.format(" font-size: %dpt;%n", fontheight);
+
+ // Font color is handled with the other colors
+ }
+
+ private String styleName(CellStyle style) {
+ if (style == null) {
+ style = wb.getCellStyleAt((short) 0);
+ }
+ StringBuilder sb = new StringBuilder();
+ try (Formatter fmt = new Formatter(sb, Locale.ROOT)) {
+ fmt.format("style_%02x", style.getIndex());
+ return fmt.toString();
+ }
+ }
+
+ private <K> void styleOut(String attr, K key, Map<K, String> mapping) {
+ String value = mapping.get(key);
+ if (value != null) {
+ out.format(" %s: %s;%n", attr, value);
+ }
+ }
+
+ private static CellType ultimateCellType(Cell c) {
+ CellType type = c.getCellType();
+ if (type == CellType.FORMULA) {
+ type = c.getCachedFormulaResultType();
+ }
+ return type;
+ }
+
+ private void printSheets() {
+ ensureOut();
+ Sheet sheet = wb.getSheetAt(0);
+ printSheet(sheet);
+ }
+
+ public void printSheet(Sheet sheet) {
+ ensureOut();
+ Map<Integer, Integer> widths = computeWidths(sheet);
+ int tableWidth = widths.get(IDX_TABLE_WIDTH);
+ out.format("<table class=%s style=\"width:%dpx;\">%n", DEFAULTS_CLASS, tableWidth);
+ printCols(widths);
+ printSheetContent(sheet);
+ out.format("</table>%n");
+ }
+
+ /**
+ * computes the column widths, defined by the sheet.
+ *
+ * @param sheet The sheet for which to compute widths
+ * @return Map with key: column index; value: column width in pixels
+ * <br>special keys:
+ * <br>{@link #IDX_HEADER_COL_WIDTH} - width of the header column
+ * <br>{@link #IDX_TABLE_WIDTH} - width of the entire table
+ */
+ private Map<Integer, Integer> computeWidths(Sheet sheet) {
+ Map<Integer, Integer> ret = new TreeMap<>();
+ int tableWidth = 0;
+
+ ensureColumnBounds(sheet);
+
+ // compute width of the header column
+ int lastRowNum = sheet.getLastRowNum();
+ int headerCharCount = String.valueOf(lastRowNum).length();
+ int headerColWidth = widthToPixels((headerCharCount + 1) * 256.0);
+ ret.put(IDX_HEADER_COL_WIDTH, headerColWidth);
+ tableWidth += headerColWidth;
+
+ for (int i = firstColumn; i < endColumn; i++) {
+ int colWidth = widthToPixels(sheet.getColumnWidth(i));
+ ret.put(i, colWidth);
+ tableWidth += colWidth;
+ }
+
+ ret.put(IDX_TABLE_WIDTH, tableWidth);
+ return ret ;
+ }
+
+ /**
+ * Probably platform-specific, but appears to be a close approximation on some systems
+ * @param widthUnits POI's native width unit (twips)
+ * @return the approximate number of pixels for a typical display
+ */
+ protected int widthToPixels(final double widthUnits) {
+ return Math.toIntExact(Math.round(widthUnits * 9 / 256));
+ }
+
+ private void printCols(Map<Integer, Integer> widths) {
+ int headerColWidth = widths.get(IDX_HEADER_COL_WIDTH);
+ out.format("<col style=\"width:%dpx\"/>%n", headerColWidth);
+ for (int i = firstColumn; i < endColumn; i++) {
+ int colWidth = widths.get(i);
+ out.format("<col style=\"width:%dpx;\"/>%n", colWidth);
+ }
+ }
+
+ private void ensureColumnBounds(Sheet sheet) {
+ if (gotBounds) {
+ return;
+ }
+
+ Iterator<Row> iter = sheet.rowIterator();
+ firstColumn = (iter.hasNext() ? Integer.MAX_VALUE : 0);
+ endColumn = 0;
+ while (iter.hasNext()) {
+ Row row = iter.next();
+ short firstCell = row.getFirstCellNum();
+ if (firstCell >= 0) {
+ firstColumn = Math.min(firstColumn, firstCell);
+ endColumn = Math.max(endColumn, row.getLastCellNum());
+ }
+ }
+ gotBounds = true;
+ }
+
+ private void printColumnHeads() {
+ out.format("<thead>%n");
+ out.format(" <tr class=%s>%n", COL_HEAD_CLASS);
+ out.format(" <th class=%s>&#x25CA;</th>%n", COL_HEAD_CLASS);
+ //noinspection UnusedDeclaration
+ StringBuilder colName = new StringBuilder();
+ for (int i = firstColumn; i < endColumn; i++) {
+ colName.setLength(0);
+ int cnum = i;
+ do {
+ colName.insert(0, (char) ('A' + cnum % 26));
+ cnum /= 26;
+ } while (cnum > 0);
+ out.format(" <th class=%s>%s</th>%n", COL_HEAD_CLASS, colName);
+ }
+ out.format(" </tr>%n");
+ out.format("</thead>%n");
+ }
+
+ private void printSheetContent(Sheet sheet) {
+ printColumnHeads();
+
+ out.format("<tbody>%n");
+ Iterator<Row> rows = sheet.rowIterator();
+ while (rows.hasNext()) {
+ Row row = rows.next();
+
+ out.format(" <tr>%n");
+ out.format(" <td class=%s>%d</td>%n", ROW_HEAD_CLASS,
+ row.getRowNum() + 1);
+ for (int i = firstColumn; i < endColumn; i++) {
+ String content = "&nbsp;";
+ String attrs = "";
+ CellStyle style = null;
+ if (i >= row.getFirstCellNum() && i < row.getLastCellNum()) {
+ Cell cell = row.getCell(i);
+ if (cell != null) {
+ style = cell.getCellStyle();
+ attrs = tagStyle(cell, style);
+ //Set the value that is rendered for the cell
+ //also applies the format
+ CellFormat cf = CellFormat.getInstance(
+ style.getDataFormatString());
+ CellFormatResult result = cf.apply(cell);
+ content = result.text; //never null
+ if (content.isEmpty()) {
+ content = "&nbsp;";
+ }
+ }
+ }
+ out.format(" <td class=%s %s>%s</td>%n", styleName(style),
+ attrs, content);
+ }
+ out.format(" </tr>%n");
+ }
+ out.format("</tbody>%n");
+ }
+
+ private String tagStyle(Cell cell, CellStyle style) {
+ if (style.getAlignment() == HorizontalAlignment.GENERAL) {
+ switch (ultimateCellType(cell)) {
+ case STRING:
+ return "style=\"text-align: left;\"";
+ case BOOLEAN:
+ case ERROR:
+ return "style=\"text-align: center;\"";
+ case NUMERIC:
+ default:
+ // "right" is the default
+ break;
+ }
+ }
+ return "";
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/ss/html/XSSFHtmlHelper.java b/poi-examples/src/main/java/org/apache/poi/examples/ss/html/XSSFHtmlHelper.java
new file mode 100644
index 0000000000..40bd504818
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/ss/html/XSSFHtmlHelper.java
@@ -0,0 +1,59 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.ss.html;
+
+import java.util.Formatter;
+
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.xssf.usermodel.XSSFCellStyle;
+import org.apache.poi.xssf.usermodel.XSSFColor;
+
+/**
+ * Implementation of {@link HtmlHelper} for XSSF files.
+ *
+ * @author Ken Arnold, Industrious Media LLC
+ */
+public class XSSFHtmlHelper implements HtmlHelper {
+ @Override
+ public void colorStyles(CellStyle style, Formatter out) {
+ XSSFCellStyle cs = (XSSFCellStyle) style;
+ styleColor(out, "background-color", cs.getFillForegroundXSSFColor());
+ styleColor(out, "text-color", cs.getFont().getXSSFColor());
+ }
+
+ private void styleColor(Formatter out, String attr, XSSFColor color) {
+ if (color == null || color.isAuto()) {
+ return;
+ }
+
+ byte[] rgb = color.getRGB();
+ if (rgb == null) {
+ return;
+ }
+
+ // This is done twice -- rgba is new with CSS 3, and browser that don't
+ // support it will ignore the rgba specification and stick with the
+ // solid color, which is declared first
+ out.format(" %s: #%02x%02x%02x;%n", attr, rgb[0], rgb[1], rgb[2]);
+ byte[] argb = color.getARGB();
+ if (argb == null) {
+ return;
+ }
+ out.format(" %s: rgba(0x%02x, 0x%02x, 0x%02x, 0x%02x);%n", attr,
+ argb[3], argb[0], argb[1], argb[2]);
+ }
+} \ No newline at end of file
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/ss/html/excelStyle.css b/poi-examples/src/main/java/org/apache/poi/examples/ss/html/excelStyle.css
new file mode 100644
index 0000000000..f056123780
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/ss/html/excelStyle.css
@@ -0,0 +1,73 @@
+/*
+ ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ ====================================================================
+ */
+/*
+ * This is the default style sheet for html generated by ToHtml
+ *
+ * @author Ken Arnold, Industrious Media LLC
+ */
+.excelDefaults {
+ background-color: white;
+ color: black;
+ text-decoration: none;
+ direction: ltr;
+ text-transform: none;
+ text-indent: 0;
+ letter-spacing: 0;
+ word-spacing: 0;
+ white-space: pre-wrap;
+ unicode-bidi: normal;
+ background-image: none;
+ text-shadow: none;
+ list-style-image: none;
+ list-style-type: none;
+ padding: 0;
+ margin: 0;
+ border-collapse: collapse;
+ vertical-align: bottom;
+ font-style: normal;
+ font-family: sans-serif;
+ font-variant: normal;
+ font-weight: normal;
+ font-size: 10pt;
+ text-align: right;
+ table-layout: fixed;
+ word-wrap: break-word;
+ overflow-wrap: break-word;
+}
+
+.excelDefaults td {
+ padding: 1px 5px;
+ border: 1px solid silver;
+}
+
+.excelDefaults .colHeader {
+ background-color: silver;
+ font-weight: bold;
+ border: 1px solid black;
+ text-align: center;
+ padding: 1px 5px;
+}
+
+.excelDefaults .rowHeader {
+ background-color: silver;
+ font-weight: bold;
+ border: 1px solid black;
+ text-align: right;
+ padding: 1px 5px;
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/ss/html/package-info.java b/poi-examples/src/main/java/org/apache/poi/examples/ss/html/package-info.java
new file mode 100644
index 0000000000..1b41376632
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/ss/html/package-info.java
@@ -0,0 +1,22 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+/**
+ * This package contains an example that uses POI to convert a workbook into
+ * an HTML representation of the data. It can use both XSSF and HSSF workbooks.
+ */
+package org.apache.poi.examples.ss.html; \ No newline at end of file
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/util/TempFileUtils.java b/poi-examples/src/main/java/org/apache/poi/examples/util/TempFileUtils.java
new file mode 100644
index 0000000000..7d2d01b409
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/util/TempFileUtils.java
@@ -0,0 +1,47 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.util;
+
+import java.io.File;
+
+import org.apache.poi.util.TempFile;
+
+public final class TempFileUtils {
+ private TempFileUtils() {
+ }
+
+ @SuppressWarnings("java:S106")
+ public static void checkTempFiles() {
+ String tmpDir = System.getProperty(TempFile.JAVA_IO_TMPDIR) + "/poifiles";
+ File tempDir = new File(tmpDir);
+ if(tempDir.exists()) {
+ String[] tempFiles = tempDir.list();
+ if(tempFiles != null && tempFiles.length > 0) {
+ System.out.println("found files in poi temp dir " + tempDir.getAbsolutePath());
+ for(String filename : tempFiles) {
+ System.out.println("file: " + filename);
+ }
+ }
+ } else {
+ System.out.println("unable to find poi temp dir");
+ }
+ }
+}
+
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xslf/AddVideoToPptx.java.txt b/poi-examples/src/main/java/org/apache/poi/examples/xslf/AddVideoToPptx.java.txt
new file mode 100644
index 0000000000..2d32c4d81b
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xslf/AddVideoToPptx.java.txt
@@ -0,0 +1,251 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.xslf.usermodel;
+
+import java.awt.Rectangle;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URL;
+import java.text.DecimalFormat;
+
+import javax.imageio.ImageIO;
+import javax.xml.namespace.QName;
+
+import org.apache.poi.openxml4j.opc.PackagePart;
+import org.apache.poi.openxml4j.opc.PackagePartName;
+import org.apache.poi.openxml4j.opc.PackageRelationship;
+import org.apache.poi.openxml4j.opc.PackagingURIHelper;
+import org.apache.poi.openxml4j.opc.TargetMode;
+import org.apache.poi.sl.usermodel.PictureData.PictureType;
+import org.apache.xmlbeans.XmlCursor;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTHyperlink;
+import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelationshipId;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTApplicationNonVisualDrawingProps;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTExtension;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTSlide;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTTLCommonMediaNodeData;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTTLCommonTimeNodeData;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTTimeNodeList;
+import org.openxmlformats.schemas.presentationml.x2006.main.STTLTimeIndefinite;
+import org.openxmlformats.schemas.presentationml.x2006.main.STTLTimeNodeFillType;
+import org.openxmlformats.schemas.presentationml.x2006.main.STTLTimeNodeRestartType;
+import org.openxmlformats.schemas.presentationml.x2006.main.STTLTimeNodeType;
+
+import com.xuggle.mediatool.IMediaReader;
+import com.xuggle.mediatool.MediaListenerAdapter;
+import com.xuggle.mediatool.ToolFactory;
+import com.xuggle.mediatool.event.IVideoPictureEvent;
+import com.xuggle.xuggler.Global;
+import com.xuggle.xuggler.IContainer;
+import com.xuggle.xuggler.io.InputOutputStreamHandler;
+
+/**
+ * Adding multiple videos to a slide
+ *
+ * need the Xuggler 5.4 jars:
+ * &lt;repositories&gt;
+ * &lt;repository&gt;
+ * &lt;id&gt;xuggle repo&lt;/id&gt;
+ * &lt;url&gt;http://xuggle.googlecode.com/svn/trunk/repo/share/java/&lt;/url&gt;
+ * &lt;/repository&gt;
+ * &lt;/repositories&gt;
+ * ...
+ * &lt;dependency&gt;
+ * &lt;groupId&gt;xuggle&lt;/groupId&gt;
+ * &lt;artifactId&gt;xuggle-xuggler&lt;/artifactId&gt;
+ * &lt;version&gt;5.4&lt;/version&gt;
+ * &lt;/dependency&gt;
+ *
+ * @see <a href="http://stackoverflow.com/questions/15197300/apache-poi-xslf-adding-movie-to-the-slide">Apache POI XSLF Adding movie to the slide</a>
+ * @see <a href="http://apache-poi.1045710.n5.nabble.com/Question-about-embedded-video-in-PPTX-files-tt5718461.html">Question about embedded video in PPTX files</a>
+ */
+public class AddVideoToPptx {
+ static DecimalFormat df_time = new DecimalFormat("0.####");
+
+ public static void main(String[] args) throws Exception {
+ URL video = new URL("http://archive.org/download/test-mpeg/test-mpeg.mpg");
+ // URL video = new URL("file:test-mpeg.mpg");
+
+ XMLSlideShow pptx = new XMLSlideShow();
+
+ // add video file
+ String videoFileName = video.getPath().substring(video.getPath().lastIndexOf('/')+1);
+ PackagePartName partName = PackagingURIHelper.createPartName("/ppt/media/"+videoFileName);
+ PackagePart part = pptx.getPackage().createPart(partName, "video/mpeg");
+ OutputStream partOs = part.getOutputStream();
+ InputStream fis = video.openStream();
+ byte buf[] = new byte[1024];
+ for (int readBytes; (readBytes = fis.read(buf)) != -1; partOs.write(buf, 0, readBytes));
+ fis.close();
+ partOs.close();
+
+ XSLFSlide slide1 = pptx.createSlide();
+ XSLFPictureShape pv1 = addPreview(pptx, slide1, part, 5, 50, 50);
+ addVideo(pptx, slide1, part, pv1, 5);
+ addTimingInfo(slide1, pv1);
+ XSLFPictureShape pv2 = addPreview(pptx, slide1, part, 9, 50, 250);
+ addVideo(pptx, slide1, part, pv2, 9);
+ addTimingInfo(slide1, pv2);
+
+ FileOutputStream fos = new FileOutputStream("pptx-with-video.pptx");
+ pptx.write(fos);
+ fos.close();
+
+ pptx.close();
+ }
+
+ static XSLFPictureShape addPreview(XMLSlideShow pptx, XSLFSlide slide1, PackagePart videoPart, double seconds, int x, int y) throws IOException {
+ // get preview after 5 sec.
+ IContainer ic = IContainer.make();
+ InputOutputStreamHandler iosh = new InputOutputStreamHandler(videoPart.getInputStream());
+ if (ic.open(iosh, IContainer.Type.READ, null) < 0) return null;
+
+ IMediaReader mediaReader = ToolFactory.makeReader(ic);
+
+ // stipulate that we want BufferedImages created in BGR 24bit color space
+ mediaReader.setBufferedImageTypeToGenerate(BufferedImage.TYPE_3BYTE_BGR);
+
+ ImageSnapListener isl = new ImageSnapListener(seconds);
+ mediaReader.addListener(isl);
+
+ // read out the contents of the media file and
+ // dispatch events to the attached listener
+ while (!isl.hasFired && mediaReader.readPacket() == null) ;
+
+ mediaReader.close();
+ ic.close();
+
+ // add snapshot
+ BufferedImage image1 = isl.image;
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ ImageIO.write(image1, "jpeg", bos);
+ XSLFPictureData snap = pptx.addPicture(bos.toByteArray(), PictureType.JPEG);
+ XSLFPictureShape pic1 = slide1.createPicture(snap);
+ pic1.setAnchor(new Rectangle(x, y, image1.getWidth(), image1.getHeight()));
+ return pic1;
+ }
+
+ static void addVideo(XMLSlideShow pptx, XSLFSlide slide1, PackagePart videoPart, XSLFPictureShape pic1, double seconds) throws IOException {
+
+ // add video shape
+ PackagePartName partName = videoPart.getPartName();
+ PackageRelationship prsEmbed1 = slide1.getPackagePart().addRelationship(partName, TargetMode.INTERNAL, "http://schemas.microsoft.com/office/2007/relationships/media");
+ PackageRelationship prsExec1 = slide1.getPackagePart().addRelationship(partName, TargetMode.INTERNAL, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/video");
+ CTPicture xpic1 = (CTPicture)pic1.getXmlObject();
+ CTHyperlink link1 = xpic1.getNvPicPr().getCNvPr().addNewHlinkClick();
+ link1.setId("");
+ link1.setAction("ppaction://media");
+
+ // add video relation
+ CTApplicationNonVisualDrawingProps nvPr = xpic1.getNvPicPr().getNvPr();
+ nvPr.addNewVideoFile().setLink(prsExec1.getId());
+ CTExtension ext = nvPr.addNewExtLst().addNewExt();
+ // see http://msdn.microsoft.com/en-us/library/dd950140(v=office.12).aspx
+ ext.setUri("{DAA4B4D4-6D71-4841-9C94-3DE7FCFB9230}");
+ String p14Ns = "http://schemas.microsoft.com/office/powerpoint/2010/main";
+ XmlCursor cur = ext.newCursor();
+ cur.toEndToken();
+ cur.beginElement(new QName(p14Ns, "media", "p14"));
+ cur.insertNamespace("p14", p14Ns);
+ cur.insertAttributeWithValue(new QName(STRelationshipId.type.getName().getNamespaceURI(), "embed"), prsEmbed1.getId());
+ cur.beginElement(new QName(p14Ns, "trim", "p14"));
+ cur.insertAttributeWithValue("st", df_time.format(seconds*1000.0));
+ cur.dispose();
+
+ }
+
+ static void addTimingInfo(XSLFSlide slide1, XSLFPictureShape pic1) {
+ // add slide timing information, so video can be controlled
+ CTSlide xslide = slide1.getXmlObject();
+ CTTimeNodeList ctnl;
+ if (!xslide.isSetTiming()) {
+ CTTLCommonTimeNodeData ctn = xslide.addNewTiming().addNewTnLst().addNewPar().addNewCTn();
+ ctn.setDur(STTLTimeIndefinite.INDEFINITE);
+ ctn.setRestart(STTLTimeNodeRestartType.NEVER);
+ ctn.setNodeType(STTLTimeNodeType.TM_ROOT);
+ ctnl = ctn.addNewChildTnLst();
+ } else {
+ ctnl = xslide.getTiming().getTnLst().getParArray(0).getCTn().getChildTnLst();
+ }
+
+ CTTLCommonMediaNodeData cmedia = ctnl.addNewVideo().addNewCMediaNode();
+ cmedia.setVol(80000);
+ CTTLCommonTimeNodeData ctn = cmedia.addNewCTn();
+ ctn.setFill(STTLTimeNodeFillType.HOLD);
+ ctn.setDisplay(false);
+ ctn.addNewStCondLst().addNewCond().setDelay(STTLTimeIndefinite.INDEFINITE);
+ cmedia.addNewTgtEl().addNewSpTgt().setSpid(""+pic1.getShapeId());
+ }
+
+
+ static class ImageSnapListener extends MediaListenerAdapter {
+ final double SECONDS_BETWEEN_FRAMES;
+ final long MICRO_SECONDS_BETWEEN_FRAMES;
+ boolean hasFired = false;
+ BufferedImage image = null;
+
+ // The video stream index, used to ensure we display frames from one and
+ // only one video stream from the media container.
+ int mVideoStreamIndex = -1;
+
+ // Time of last frame write
+ long mLastPtsWrite = Global.NO_PTS;
+
+ public ImageSnapListener(double seconds) {
+ SECONDS_BETWEEN_FRAMES = seconds;
+ MICRO_SECONDS_BETWEEN_FRAMES =
+ (long)(Global.DEFAULT_PTS_PER_SECOND * SECONDS_BETWEEN_FRAMES);
+ }
+
+
+ @Override
+ public void onVideoPicture(IVideoPictureEvent event) {
+
+ if (event.getStreamIndex() != mVideoStreamIndex) {
+ // if the selected video stream id is not yet set, go ahead an
+ // select this lucky video stream
+ if (mVideoStreamIndex != -1) return;
+ mVideoStreamIndex = event.getStreamIndex();
+ }
+
+ long evtTS = event.getTimeStamp();
+
+ // if uninitialized, back date mLastPtsWrite to get the very first frame
+ if (mLastPtsWrite == Global.NO_PTS)
+ mLastPtsWrite = Math.max(0, evtTS - MICRO_SECONDS_BETWEEN_FRAMES);
+
+ // if it's time to write the next frame
+ if (evtTS - mLastPtsWrite >= MICRO_SECONDS_BETWEEN_FRAMES) {
+ if (!hasFired) {
+ image = event.getImage();
+ hasFired = true;
+ }
+ // update last write time
+ mLastPtsWrite += MICRO_SECONDS_BETWEEN_FRAMES;
+ }
+ }
+ }
+
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xslf/BarChartDemo.java b/poi-examples/src/main/java/org/apache/poi/examples/xslf/BarChartDemo.java
new file mode 100644
index 0000000000..2c159fbb59
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xslf/BarChartDemo.java
@@ -0,0 +1,169 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.xslf;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.ooxml.POIXMLDocumentPart;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xddf.usermodel.chart.AxisOrientation;
+import org.apache.poi.xddf.usermodel.chart.AxisPosition;
+import org.apache.poi.xddf.usermodel.chart.BarDirection;
+import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
+import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFChart;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+
+/**
+ * Build a bar chart from a template pptx
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class BarChartDemo {
+ private BarChartDemo() {}
+
+ private static void usage(){
+ System.out.println("Usage: BarChartDemo <bar-chart-template.pptx> <bar-chart-data.txt>");
+ System.out.println(" bar-chart-template.pptx template with a bar chart");
+ System.out.println(" bar-chart-data.txt the model to set. First line is chart title, " +
+ "then go pairs {axis-label value}");
+ }
+
+ public static void main(String[] args) throws Exception {
+ if(args.length < 2) {
+ usage();
+ return;
+ }
+
+ try (FileInputStream argIS = new FileInputStream(args[0]);
+ BufferedReader modelReader = Files.newBufferedReader(Paths.get(args[1]), StandardCharsets.UTF_8)) {
+
+ String chartTitle = modelReader.readLine(); // first line is chart title
+ String[] series = modelReader.readLine().split(",");
+
+ // Category Axis Data
+ List<String> listLanguages = new ArrayList<>(10);
+
+ // Values
+ List<Double> listCountries = new ArrayList<>(10);
+ List<Double> listSpeakers = new ArrayList<>(10);
+
+ // set model
+ String ln;
+ while((ln = modelReader.readLine()) != null) {
+ String[] vals = ln.split(",");
+ listCountries.add(Double.valueOf(vals[0]));
+ listSpeakers.add(Double.valueOf(vals[1]));
+ listLanguages.add(vals[2]);
+ }
+ String[] categories = listLanguages.toArray(new String[0]);
+ Double[] values1 = listCountries.toArray(new Double[0]);
+ Double[] values2 = listSpeakers.toArray(new Double[0]);
+
+ try (XMLSlideShow pptx = new XMLSlideShow(argIS)) {
+ XSLFSlide slide = pptx.getSlides().get(0);
+ setBarData(findChart(slide), chartTitle, series, categories, values1, values2);
+
+ XSLFChart chart = findChart(pptx.createSlide().importContent(slide));
+ setColumnData(chart, "Column variant");
+
+ // save the result
+ try (OutputStream out = new FileOutputStream("bar-chart-demo-output.pptx")) {
+ pptx.write(out);
+ }
+ }
+ }
+ }
+
+ private static void setBarData(XSLFChart chart, String chartTitle, String[] series, String[] categories, Double[] values1, Double[] values2) {
+ final List<XDDFChartData> data = chart.getChartSeries();
+ final XDDFBarChartData bar = (XDDFBarChartData) data.get(0);
+
+ final int numOfPoints = categories.length;
+ final String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, COLUMN_LANGUAGES, COLUMN_LANGUAGES));
+ final String valuesDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, COLUMN_COUNTRIES, COLUMN_COUNTRIES));
+ final String valuesDataRange2 = chart.formatRange(new CellRangeAddress(1, numOfPoints, COLUMN_SPEAKERS, COLUMN_SPEAKERS));
+ final XDDFDataSource<?> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, COLUMN_LANGUAGES);
+ final XDDFNumericalDataSource<? extends Number> valuesData = XDDFDataSourcesFactory.fromArray(values1, valuesDataRange, COLUMN_COUNTRIES);
+ values1[6] = 16.0; // if you ever want to change the underlying data, it has to be done before building the data source
+ final XDDFNumericalDataSource<? extends Number> valuesData2 = XDDFDataSourcesFactory.fromArray(values2, valuesDataRange2, COLUMN_SPEAKERS);
+
+ XDDFChartData.Series series1 = bar.getSeries(0);
+ series1.replaceData(categoriesData, valuesData);
+ series1.setTitle(series[0], chart.setSheetTitle(series[0], COLUMN_COUNTRIES));
+ XDDFChartData.Series series2 = bar.addSeries(categoriesData, valuesData2);
+ series2.setTitle(series[1], chart.setSheetTitle(series[1], COLUMN_SPEAKERS));
+
+ chart.plot(bar);
+ chart.setTitleText(chartTitle); // https://stackoverflow.com/questions/30532612
+ // chart.setTitleOverlay(overlay);
+
+ // adjust font size for readability
+ bar.getCategoryAxis().getOrAddTextProperties().setFontSize(11.5);
+ chart.getTitle().getOrAddTextProperties().setFontSize(18.2);
+ }
+
+ private static void setColumnData(XSLFChart chart, String chartTitle) {
+ // Series Text
+ List<XDDFChartData> series = chart.getChartSeries();
+ XDDFBarChartData bar = (XDDFBarChartData) series.get(0);
+
+ // in order to transform a bar chart into a column chart, you just need to change the bar direction
+ bar.setBarDirection(BarDirection.COL);
+
+ // looking for "Stacked Bar Chart"? uncomment the following line
+ // bar.setBarGrouping(BarGrouping.STACKED);
+
+ // additionally, you can adjust the axes
+ bar.getCategoryAxis().setOrientation(AxisOrientation.MAX_MIN);
+ bar.getValueAxes().get(0).setPosition(AxisPosition.TOP);
+ }
+
+ private static XSLFChart findChart(XSLFSlide slide) {
+ // find chart in the slide
+ XSLFChart chart = null;
+ for(POIXMLDocumentPart part : slide.getRelations()){
+ if(part instanceof XSLFChart){
+ chart = (XSLFChart) part;
+ break;
+ }
+ }
+
+ if(chart == null) {
+ throw new IllegalStateException("chart not found in the template");
+ }
+ return chart;
+ }
+
+ private static final int COLUMN_LANGUAGES = 0;
+ private static final int COLUMN_COUNTRIES = 1;
+ private static final int COLUMN_SPEAKERS = 2;
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xslf/ChartFromScratch.java b/poi-examples/src/main/java/org/apache/poi/examples/xslf/ChartFromScratch.java
new file mode 100644
index 0000000000..bdfc3ea498
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xslf/ChartFromScratch.java
@@ -0,0 +1,187 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.xslf;
+
+import java.awt.geom.Rectangle2D;
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.util.Units;
+import org.apache.poi.xddf.usermodel.chart.AxisCrossBetween;
+import org.apache.poi.xddf.usermodel.chart.AxisCrosses;
+import org.apache.poi.xddf.usermodel.chart.AxisPosition;
+import org.apache.poi.xddf.usermodel.chart.AxisTickMark;
+import org.apache.poi.xddf.usermodel.chart.BarDirection;
+import org.apache.poi.xddf.usermodel.chart.BarGrouping;
+import org.apache.poi.xddf.usermodel.chart.ChartTypes;
+import org.apache.poi.xddf.usermodel.chart.LegendPosition;
+import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFChartAxis;
+import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
+import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFChart;
+import org.apache.poi.xslf.usermodel.XSLFGraphicFrame;
+import org.apache.poi.xslf.usermodel.XSLFShape;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+
+/**
+ * Build a chart without reading template file
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class ChartFromScratch {
+ private ChartFromScratch() {}
+
+ private static void usage(){
+ System.out.println("Usage: ChartFromScratch <bar-chart-data.txt>");
+ System.out.println(" bar-chart-data.txt the model to set. First line is chart title, " +
+ "then go pairs {axis-label value}");
+ }
+
+ public static void main(String[] args) throws Exception {
+ if(args.length < 1) {
+ usage();
+ return;
+ }
+
+ try (BufferedReader modelReader = Files.newBufferedReader(Paths.get(args[0]), StandardCharsets.UTF_8)) {
+
+ String chartTitle = modelReader.readLine(); // first line is chart title
+ String[] series = modelReader.readLine().split(",");
+
+ // Category Axis Data
+ List<String> listLanguages = new ArrayList<>(10);
+
+ // Values
+ List<Double> listCountries = new ArrayList<>(10);
+ List<Double> listSpeakers = new ArrayList<>(10);
+
+ // set model
+ String ln;
+ while((ln = modelReader.readLine()) != null) {
+ String[] vals = ln.split(",");
+ listCountries.add(Double.valueOf(vals[0]));
+ listSpeakers.add(Double.valueOf(vals[1]));
+ listLanguages.add(vals[2]);
+ }
+
+ String[] categories = listLanguages.toArray(new String[0]);
+ Double[] values1 = listCountries.toArray(new Double[0]);
+ Double[] values2 = listSpeakers.toArray(new Double[0]);
+
+ try (XMLSlideShow ppt = new XMLSlideShow()) {
+ createSlideWithChart(ppt, chartTitle, series, categories, values1, values2);
+ createSlideWithChart(ppt, chartTitle, series, categories, values1, values2);
+ createSlideWithChart(ppt, chartTitle, series, categories, values1, values2);
+ // save the result
+ try (OutputStream out = new FileOutputStream("chart-from-scratch.pptx")) {
+ ppt.write(out);
+ }
+ }
+ try (FileInputStream is = new FileInputStream("chart-from-scratch.pptx")) {
+ try (XMLSlideShow ppt = new XMLSlideShow(is)) {
+ for (XSLFSlide slide : ppt.getSlides()) {
+ for (XSLFShape shape : slide.getShapes()) {
+ if (shape instanceof XSLFGraphicFrame) {
+ XSLFGraphicFrame frame = (XSLFGraphicFrame) shape;
+ if (frame.hasChart()) {
+ System.out.println(frame.getChart().getTitleShape().getText());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ System.out.println("Done");
+ }
+
+ private static void createSlideWithChart(XMLSlideShow ppt, String chartTitle, String[] series, String[] categories,
+ Double[] values1, Double[] values2) {
+ XSLFSlide slide = ppt.createSlide();
+ XSLFChart chart = ppt.createChart();
+ Rectangle2D rect2D = new java.awt.Rectangle(fromCM(1.5), fromCM(4), fromCM(22), fromCM(14));
+ slide.addChart(chart, rect2D);
+ setBarData(chart, chartTitle, series, categories, values1, values2);
+ }
+
+ private static int fromCM(double cm) {
+ return (int) (Math.rint(cm * Units.EMU_PER_CENTIMETER));
+ }
+
+ private static void setBarData(XSLFChart chart, String chartTitle, String[] series, String[] categories, Double[] values1, Double[] values2) {
+ // Use a category axis for the bottom axis.
+ XDDFChartAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
+ bottomAxis.setTitle(series[2]);
+ XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
+ leftAxis.setTitle(series[0]+","+series[1]);
+ leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
+ leftAxis.setMajorTickMark(AxisTickMark.OUT);
+ leftAxis.setCrossBetween(AxisCrossBetween.BETWEEN);
+
+ final int numOfPoints = categories.length;
+ final String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, COLUMN_LANGUAGES, COLUMN_LANGUAGES));
+ final String valuesDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, COLUMN_COUNTRIES, COLUMN_COUNTRIES));
+ final String valuesDataRange2 = chart.formatRange(new CellRangeAddress(1, numOfPoints, COLUMN_SPEAKERS, COLUMN_SPEAKERS));
+ final XDDFDataSource<?> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, COLUMN_LANGUAGES);
+ final XDDFNumericalDataSource<? extends Number> valuesData = XDDFDataSourcesFactory.fromArray(values1, valuesDataRange, COLUMN_COUNTRIES);
+ valuesData.setFormatCode("General");
+ values1[6] = 16.0; // if you ever want to change the underlying data, it has to be done before building the data source
+ final XDDFNumericalDataSource<? extends Number> valuesData2 = XDDFDataSourcesFactory.fromArray(values2, valuesDataRange2, COLUMN_SPEAKERS);
+ valuesData2.setFormatCode("General");
+
+
+ XDDFBarChartData bar = (XDDFBarChartData) chart.createData(ChartTypes.BAR, bottomAxis, leftAxis);
+ bar.setBarGrouping(BarGrouping.CLUSTERED);
+
+ XDDFBarChartData.Series series1 = (XDDFBarChartData.Series) bar.addSeries(categoriesData, valuesData);
+ series1.setTitle(series[0], chart.setSheetTitle(series[COLUMN_COUNTRIES - 1], COLUMN_COUNTRIES));
+
+ XDDFBarChartData.Series series2 = (XDDFBarChartData.Series) bar.addSeries(categoriesData, valuesData2);
+ series2.setTitle(series[1], chart.setSheetTitle(series[COLUMN_SPEAKERS - 1], COLUMN_SPEAKERS));
+
+ bar.setVaryColors(true);
+ bar.setBarDirection(BarDirection.COL);
+ chart.plot(bar);
+
+ XDDFChartLegend legend = chart.getOrAddLegend();
+ legend.setPosition(LegendPosition.LEFT);
+ legend.setOverlay(false);
+
+ chart.setTitleText(chartTitle);
+ chart.setTitleOverlay(false);
+ chart.setAutoTitleDeleted(false);
+ }
+
+ private static final int COLUMN_LANGUAGES = 0;
+ private static final int COLUMN_COUNTRIES = 1;
+ private static final int COLUMN_SPEAKERS = 2;
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xslf/DataExtraction.java b/poi-examples/src/main/java/org/apache/poi/examples/xslf/DataExtraction.java
new file mode 100644
index 0000000000..40a7c7f0d9
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xslf/DataExtraction.java
@@ -0,0 +1,101 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.xslf;
+
+import java.awt.Dimension;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+
+import org.apache.poi.openxml4j.opc.PackagePart;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFPictureData;
+import org.apache.poi.xslf.usermodel.XSLFPictureShape;
+import org.apache.poi.xslf.usermodel.XSLFShape;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+import org.apache.poi.xslf.usermodel.XSLFTextShape;
+
+/**
+ * Demonstrates how you can extract data from a .pptx file
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class DataExtraction {
+ private DataExtraction() {}
+
+ public static void main(String[] args) throws IOException {
+
+ PrintStream out = System.out;
+
+ if (args.length == 0) {
+ out.println("Input file is required");
+ return;
+ }
+
+ FileInputStream is = new FileInputStream(args[0]);
+ try (XMLSlideShow ppt = new XMLSlideShow(is)) {
+ is.close();
+
+ // Get the document's embedded files.
+ for (PackagePart p : ppt.getAllEmbeddedParts()) {
+ String type = p.getContentType();
+ // typically file name
+ String name = p.getPartName().getName();
+ out.println("Embedded file (" + type + "): " + name);
+
+ InputStream pIs = p.getInputStream();
+ // make sense of the part data
+ pIs.close();
+
+ }
+
+ // Get the document's embedded files.
+ for (XSLFPictureData data : ppt.getPictureData()) {
+ String type = data.getContentType();
+ String name = data.getFileName();
+ out.println("Picture (" + type + "): " + name);
+
+ InputStream pIs = data.getInputStream();
+ // make sense of the image data
+ pIs.close();
+ }
+
+ // size of the canvas in points
+ Dimension pageSize = ppt.getPageSize();
+ out.println("Pagesize: " + pageSize);
+
+ for (XSLFSlide slide : ppt.getSlides()) {
+ for (XSLFShape shape : slide) {
+ if (shape instanceof XSLFTextShape) {
+ XSLFTextShape txShape = (XSLFTextShape) shape;
+ out.println(txShape.getText());
+ } else if (shape instanceof XSLFPictureShape) {
+ XSLFPictureShape pShape = (XSLFPictureShape) shape;
+ XSLFPictureData pData = pShape.getPictureData();
+ out.println(pData.getFileName());
+ } else {
+ out.println("Process me: " + shape.getClass());
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xslf/DoughnutChartFromScratch.java b/poi-examples/src/main/java/org/apache/poi/examples/xslf/DoughnutChartFromScratch.java
new file mode 100644
index 0000000000..77a438967f
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xslf/DoughnutChartFromScratch.java
@@ -0,0 +1,167 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.xslf;
+
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.util.Units;
+import org.apache.poi.xddf.usermodel.chart.AxisCrossBetween;
+import org.apache.poi.xddf.usermodel.chart.AxisCrosses;
+import org.apache.poi.xddf.usermodel.chart.AxisPosition;
+import org.apache.poi.xddf.usermodel.chart.AxisTickMark;
+import org.apache.poi.xddf.usermodel.chart.ChartTypes;
+import org.apache.poi.xddf.usermodel.chart.LegendPosition;
+import org.apache.poi.xddf.usermodel.chart.XDDFChartAxis;
+import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
+import org.apache.poi.xddf.usermodel.chart.XDDFDoughnutChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFChart;
+import org.apache.poi.xslf.usermodel.XSLFGraphicFrame;
+import org.apache.poi.xslf.usermodel.XSLFShape;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+
+import java.awt.geom.Rectangle2D;
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Build a chart without reading template file
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class DoughnutChartFromScratch {
+ private DoughnutChartFromScratch() {}
+
+ private static void usage(){
+ System.out.println("Usage: DoughnutChartFromScratch <bar-chart-data.txt>");
+ System.out.println(" bar-chart-data.txt the model to set. First line is chart title, " +
+ "then go pairs {axis-label value}");
+ }
+
+ public static void main(String[] args) throws Exception {
+ if(args.length < 1) {
+ usage();
+ return;
+ }
+
+ try (BufferedReader modelReader = Files.newBufferedReader(Paths.get(args[0]), StandardCharsets.UTF_8)) {
+
+ String chartTitle = modelReader.readLine(); // first line is chart title
+ String[] series = modelReader.readLine().split(",");
+
+ // Category Axis Data
+ List<String> listLanguages = new ArrayList<>(10);
+
+ // Values
+ List<Double> listCountries = new ArrayList<>(10);
+ List<Double> listSpeakers = new ArrayList<>(10);
+
+ // set model
+ String ln;
+ while((ln = modelReader.readLine()) != null) {
+ String[] vals = ln.split(",");
+ listCountries.add(Double.valueOf(vals[0]));
+ listSpeakers.add(Double.valueOf(vals[1]));
+ listLanguages.add(vals[2]);
+ }
+
+ String[] categories = listLanguages.toArray(new String[0]);
+ Double[] values1 = listCountries.toArray(new Double[0]);
+ Double[] values2 = listSpeakers.toArray(new Double[0]);
+
+ try (XMLSlideShow ppt = new XMLSlideShow()) {
+ createSlideWithChart(ppt, chartTitle, series, categories, values1, COLUMN_COUNTRIES);
+ createSlideWithChart(ppt, chartTitle, series, categories, values2, COLUMN_SPEAKERS);
+ // save the result
+ try (OutputStream out = new FileOutputStream("doughnut-chart-from-scratch.pptx")) {
+ ppt.write(out);
+ }
+ }
+ try (FileInputStream is = new FileInputStream("doughnut-chart-from-scratch.pptx")) {
+ try (XMLSlideShow ppt = new XMLSlideShow(is)) {
+ for (XSLFSlide slide : ppt.getSlides()) {
+ for (XSLFShape shape : slide.getShapes()) {
+ if (shape instanceof XSLFGraphicFrame) {
+ XSLFGraphicFrame frame = (XSLFGraphicFrame) shape;
+ if (frame.hasChart()) {
+ System.out.println(frame.getChart().getTitleShape().getText());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ System.out.println("Done");
+ }
+
+ private static void createSlideWithChart(XMLSlideShow ppt, String chartTitle, String[] series, String[] categories,
+ Double[] values, int valuesColumn) {
+ XSLFSlide slide = ppt.createSlide();
+ XSLFChart chart = ppt.createChart();
+ Rectangle2D rect2D = new java.awt.Rectangle(fromCM(1.5), fromCM(4), fromCM(22), fromCM(14));
+ slide.addChart(chart, rect2D);
+ setDoughnutData(chart, chartTitle, series, categories, values, valuesColumn);
+ }
+
+ private static int fromCM(double cm) {
+ return (int) (Math.rint(cm * Units.EMU_PER_CENTIMETER));
+ }
+
+ private static void setDoughnutData(XSLFChart chart, String chartTitle, String[] series, String[] categories,
+ Double[] values, int valuesColumn) {
+ final int numOfPoints = categories.length;
+ final String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, COLUMN_LANGUAGES, COLUMN_LANGUAGES));
+ final String valuesDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, valuesColumn, valuesColumn));
+ final XDDFDataSource<?> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, COLUMN_LANGUAGES);
+ final XDDFNumericalDataSource<? extends Number> valuesData = XDDFDataSourcesFactory.fromArray(values, valuesDataRange, valuesColumn);
+ valuesData.setFormatCode("General");
+
+ XDDFDoughnutChartData data = (XDDFDoughnutChartData) chart.createData(ChartTypes.DOUGHNUT, null, null);
+ XDDFDoughnutChartData.Series series1 = (XDDFDoughnutChartData.Series) data.addSeries(categoriesData, valuesData);
+ series1.setTitle(series[0], chart.setSheetTitle(series[valuesColumn - 1], valuesColumn));
+
+ data.setVaryColors(true);
+ data.setHoleSize(42);
+ data.setFirstSliceAngle(90);
+ chart.plot(data);
+
+ XDDFChartLegend legend = chart.getOrAddLegend();
+ legend.setPosition(LegendPosition.LEFT);
+ legend.setOverlay(false);
+
+ chart.setTitleText(chartTitle);
+ chart.setTitleOverlay(false);
+ chart.setAutoTitleDeleted(false);
+ }
+
+ private static final int COLUMN_LANGUAGES = 0;
+ private static final int COLUMN_COUNTRIES = 1;
+ private static final int COLUMN_SPEAKERS = 2;
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xslf/LinkVideoToPptx.java b/poi-examples/src/main/java/org/apache/poi/examples/xslf/LinkVideoToPptx.java
new file mode 100644
index 0000000000..9fcf312011
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xslf/LinkVideoToPptx.java
@@ -0,0 +1,120 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.xslf;
+
+import static org.apache.poi.openxml4j.opc.PackageRelationshipTypes.CORE_PROPERTIES_ECMA376_NS;
+
+import java.awt.Rectangle;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import javax.xml.namespace.QName;
+
+import org.apache.poi.openxml4j.opc.PackagePart;
+import org.apache.poi.openxml4j.opc.PackageRelationship;
+import org.apache.poi.openxml4j.opc.TargetMode;
+import org.apache.poi.sl.usermodel.PictureData;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFPictureData;
+import org.apache.poi.xslf.usermodel.XSLFPictureShape;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+import org.apache.xmlbeans.XmlCursor;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTHyperlink;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTApplicationNonVisualDrawingProps;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTExtension;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTSlide;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTTLCommonMediaNodeData;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTTLCommonTimeNodeData;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTTimeNodeList;
+import org.openxmlformats.schemas.presentationml.x2006.main.STTLTimeIndefinite;
+import org.openxmlformats.schemas.presentationml.x2006.main.STTLTimeNodeFillType;
+import org.openxmlformats.schemas.presentationml.x2006.main.STTLTimeNodeRestartType;
+import org.openxmlformats.schemas.presentationml.x2006.main.STTLTimeNodeType;
+
+public final class LinkVideoToPptx {
+ private LinkVideoToPptx() {}
+
+ public static void main(String[] args) throws IOException, URISyntaxException {
+ try (XMLSlideShow pptx = new XMLSlideShow()) {
+
+ String videoFileName = "file_example_MP4_640_3MG.mp4";
+ XSLFSlide slide1 = pptx.createSlide();
+
+ PackagePart pp = slide1.getPackagePart();
+ URI mp4uri = new URI("./" + videoFileName);
+ PackageRelationship prsEmbed1 = pp.addRelationship(mp4uri, TargetMode.EXTERNAL, "http://schemas.microsoft.com/office/2007/relationships/media");
+ PackageRelationship prsExec1 = pp.addRelationship(mp4uri, TargetMode.EXTERNAL, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/video");
+
+
+ File previewJpg = new File("preview.jpg");
+ XSLFPictureData snap = pptx.addPicture(previewJpg, PictureData.PictureType.JPEG);
+ XSLFPictureShape pic1 = slide1.createPicture(snap);
+ pic1.setAnchor(new Rectangle(100, 100, 500, 400));
+
+ CTPicture xpic1 = (CTPicture) pic1.getXmlObject();
+ CTHyperlink link1 = xpic1.getNvPicPr().getCNvPr().addNewHlinkClick();
+ link1.setId("");
+ link1.setAction("ppaction://media");
+
+
+ CTApplicationNonVisualDrawingProps nvPr = xpic1.getNvPicPr().getNvPr();
+ nvPr.addNewVideoFile().setLink(prsExec1.getId());
+ CTExtension ext = nvPr.addNewExtLst().addNewExt();
+ ext.setUri("{DAA4B4D4-6D71-4841-9C94-3DE7FCFB9230}");
+
+ String p14Ns = "http://schemas.microsoft.com/office/powerpoint/2010/main";
+ XmlCursor cur = ext.newCursor();
+ cur.toEndToken();
+ cur.beginElement(new QName(p14Ns, "media", "p14"));
+ cur.insertNamespace("p14", p14Ns);
+ cur.insertAttributeWithValue(new QName(CORE_PROPERTIES_ECMA376_NS, "link"), prsEmbed1.getId());
+ cur.dispose();
+
+
+ CTSlide xslide = slide1.getXmlObject();
+ CTTimeNodeList ctnl;
+ if (!xslide.isSetTiming()) {
+ CTTLCommonTimeNodeData ctn = xslide.addNewTiming().addNewTnLst().addNewPar().addNewCTn();
+ ctn.setDur(STTLTimeIndefinite.INDEFINITE);
+ ctn.setRestart(STTLTimeNodeRestartType.NEVER);
+ ctn.setNodeType(STTLTimeNodeType.TM_ROOT);
+ ctnl = ctn.addNewChildTnLst();
+ } else {
+ ctnl = xslide.getTiming().getTnLst().getParArray(0).getCTn().getChildTnLst();
+ }
+ CTTLCommonMediaNodeData cmedia = ctnl.addNewVideo().addNewCMediaNode();
+ cmedia.setVol(80000);
+ CTTLCommonTimeNodeData ctn = cmedia.addNewCTn();
+ ctn.setFill(STTLTimeNodeFillType.HOLD);
+ ctn.setDisplay(false);
+ ctn.addNewStCondLst().addNewCond().setDelay(STTLTimeIndefinite.INDEFINITE);
+ cmedia.addNewTgtEl().addNewSpTgt().setSpid(pic1.getShapeId());
+
+
+ try (FileOutputStream fos = new FileOutputStream("mp4test/mp4test-poi.pptx")) {
+ pptx.write(fos);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xslf/MergePresentations.java b/poi-examples/src/main/java/org/apache/poi/examples/xslf/MergePresentations.java
new file mode 100644
index 0000000000..89ae0b1aa9
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xslf/MergePresentations.java
@@ -0,0 +1,51 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.xslf;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+
+/**
+ * Merge multiple pptx presentations together
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class MergePresentations {
+ private MergePresentations() {}
+
+ public static void main(String[] args) throws Exception {
+ try (XMLSlideShow ppt = new XMLSlideShow()) {
+ for (String arg : args) {
+ try (FileInputStream is = new FileInputStream(arg);
+ XMLSlideShow src = new XMLSlideShow(is)) {
+ for (XSLFSlide srcSlide : src.getSlides()) {
+ ppt.createSlide().importContent(srcSlide);
+ }
+ }
+ }
+
+ try (FileOutputStream out = new FileOutputStream("merged.pptx")) {
+ ppt.write(out);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xslf/PieChartDemo.java b/poi-examples/src/main/java/org/apache/poi/examples/xslf/PieChartDemo.java
new file mode 100644
index 0000000000..5f3d6470c8
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xslf/PieChartDemo.java
@@ -0,0 +1,123 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.xslf;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.ooxml.POIXMLDocumentPart;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xddf.usermodel.chart.XDDFChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
+import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFPieChartData;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFChart;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+
+/**
+ * Build a pie chart from a template pptx
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class PieChartDemo {
+ private PieChartDemo() {}
+
+ private static void usage(){
+ System.out.println("Usage: PieChartDemo <pie-chart-template.pptx> <pie-chart-data.txt>");
+ System.out.println(" pie-chart-template.pptx template with a pie chart");
+ System.out.println(" pie-chart-data.txt the model to set. First line is chart title, " +
+ "then go pairs {axis-label value}");
+ }
+
+ public static void main(String[] args) throws Exception {
+ if(args.length < 2) {
+ usage();
+ return;
+ }
+
+ try (FileInputStream argIS = new FileInputStream(args[0]);
+ BufferedReader modelReader = Files.newBufferedReader(Paths.get(args[1]), StandardCharsets.UTF_8)) {
+ String chartTitle = modelReader.readLine(); // first line is chart title
+
+ try (XMLSlideShow pptx = new XMLSlideShow(argIS)) {
+ XSLFSlide slide = pptx.getSlides().get(0);
+
+ // find chart in the slide
+ XSLFChart chart = null;
+ for (POIXMLDocumentPart part : slide.getRelations()) {
+ if (part instanceof XSLFChart) {
+ chart = (XSLFChart) part;
+ break;
+ }
+ }
+
+ if(chart == null) {
+ throw new IllegalStateException("chart not found in the template");
+ }
+
+ // Series Text
+ List<XDDFChartData> series = chart.getChartSeries();
+ XDDFPieChartData pie = (XDDFPieChartData) series.get(0);
+
+ // Category Axis Data
+ List<String> listCategories = new ArrayList<>(3);
+
+ // Values
+ List<Double> listValues = new ArrayList<>(3);
+
+ // set model
+ String ln;
+ while((ln = modelReader.readLine()) != null){
+ String[] vals = ln.split("\\s+");
+ listCategories.add(vals[0]);
+ listValues.add(Double.valueOf(vals[1]));
+ }
+ String[] categories = listCategories.toArray(new String[0]);
+ Double[] values = listValues.toArray(new Double[0]);
+
+ final int numOfPoints = categories.length;
+ final String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0));
+ final String valuesDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 1, 1));
+ final XDDFDataSource<?> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange);
+ final XDDFNumericalDataSource<? extends Number> valuesData = XDDFDataSourcesFactory.fromArray(values, valuesDataRange);
+
+ XDDFPieChartData.Series firstSeries = (XDDFPieChartData.Series) pie.getSeries(0);
+ firstSeries.replaceData(categoriesData, valuesData);
+ firstSeries.setTitle(chartTitle, chart.setSheetTitle(chartTitle, 0));
+ firstSeries.setExplosion(25L);
+ firstSeries.getDataPoint(1).setExplosion(35L);
+ chart.plot(pie);
+
+ // save the result
+ try (OutputStream out = new FileOutputStream("pie-chart-demo-output.pptx")) {
+ pptx.write(out);
+ }
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xslf/Tutorial1.java b/poi-examples/src/main/java/org/apache/poi/examples/xslf/Tutorial1.java
new file mode 100644
index 0000000000..d1b4768a1c
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xslf/Tutorial1.java
@@ -0,0 +1,80 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.xslf;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.xslf.usermodel.SlideLayout;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+import org.apache.poi.xslf.usermodel.XSLFSlideLayout;
+import org.apache.poi.xslf.usermodel.XSLFSlideMaster;
+import org.apache.poi.xslf.usermodel.XSLFTextParagraph;
+import org.apache.poi.xslf.usermodel.XSLFTextShape;
+
+/**
+ * Demonstrates how to create slides with predefined layout
+ * and fill the placeholder shapes
+ */
+public final class Tutorial1 {
+ private Tutorial1() {}
+
+ public static void main(String[] args) throws IOException{
+ try (XMLSlideShow ppt = new XMLSlideShow()) {
+ // XSLFSlide#createSlide() with no arguments creates a blank slide
+ /*XSLFSlide blankSlide =*/
+ ppt.createSlide();
+
+
+ XSLFSlideMaster master = ppt.getSlideMasters().get(0);
+
+ XSLFSlideLayout layout1 = master.getLayout(SlideLayout.TITLE);
+ XSLFSlide slide1 = ppt.createSlide(layout1);
+ XSLFTextShape[] ph1 = slide1.getPlaceholders();
+ XSLFTextShape titlePlaceholder1 = ph1[0];
+ titlePlaceholder1.setText("This is a title");
+ XSLFTextShape subtitlePlaceholder1 = ph1[1];
+ subtitlePlaceholder1.setText("this is a subtitle");
+
+ XSLFSlideLayout layout2 = master.getLayout(SlideLayout.TITLE_AND_CONTENT);
+ XSLFSlide slide2 = ppt.createSlide(layout2);
+ XSLFTextShape[] ph2 = slide2.getPlaceholders();
+ XSLFTextShape titlePlaceholder2 = ph2[0];
+ titlePlaceholder2.setText("This is a title");
+ XSLFTextShape bodyPlaceholder = ph2[1];
+ // we are going to add text by paragraphs. Clear the default placehoder text before that
+ bodyPlaceholder.clearText();
+ XSLFTextParagraph p1 = bodyPlaceholder.addNewTextParagraph();
+ p1.setIndentLevel(0);
+ p1.addNewTextRun().setText("Level1 text");
+ XSLFTextParagraph p2 = bodyPlaceholder.addNewTextParagraph();
+ p2.setIndentLevel(1);
+ p2.addNewTextRun().setText("Level2 text");
+ XSLFTextParagraph p3 = bodyPlaceholder.addNewTextParagraph();
+ p3.setIndentLevel(2);
+ p3.addNewTextRun().setText("Level3 text");
+
+ try (FileOutputStream out = new FileOutputStream("slides.pptx")) {
+ ppt.write(out);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xslf/Tutorial2.java b/poi-examples/src/main/java/org/apache/poi/examples/xslf/Tutorial2.java
new file mode 100644
index 0000000000..78afd7015f
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xslf/Tutorial2.java
@@ -0,0 +1,88 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.xslf;
+
+import java.awt.Color;
+import java.awt.Rectangle;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+import org.apache.poi.xslf.usermodel.XSLFTextBox;
+import org.apache.poi.xslf.usermodel.XSLFTextParagraph;
+import org.apache.poi.xslf.usermodel.XSLFTextRun;
+
+/**
+ * Basic paragraph and text formatting
+ */
+public final class Tutorial2 {
+ private Tutorial2() {}
+
+ public static void main(String[] args) throws IOException{
+ try (XMLSlideShow ppt = new XMLSlideShow()) {
+ XSLFSlide slide1 = ppt.createSlide();
+ XSLFTextBox shape1 = slide1.createTextBox();
+ // initial height of the text box is 100 pt but
+ Rectangle anchor = new Rectangle(10, 100, 300, 100);
+ shape1.setAnchor(anchor);
+
+ XSLFTextParagraph p1 = shape1.addNewTextParagraph();
+ XSLFTextRun r1 = p1.addNewTextRun();
+ r1.setText("Paragraph Formatting");
+ r1.setFontSize(24d);
+ r1.setFontColor(new Color(85, 142, 213));
+
+ XSLFTextParagraph p2 = shape1.addNewTextParagraph();
+ // If spaceBefore >= 0, then space is a percentage of normal line height.
+ // If spaceBefore < 0, the absolute value of linespacing is the spacing in points
+ p2.setSpaceBefore(-20d); // 20 pt from the previous paragraph
+ p2.setSpaceAfter(300d); // 3 lines after the paragraph
+ XSLFTextRun r2 = p2.addNewTextRun();
+ r2.setText("Paragraph properties apply to all text residing within the corresponding paragraph.");
+ r2.setFontSize(16d);
+
+ XSLFTextParagraph p3 = shape1.addNewTextParagraph();
+
+ XSLFTextRun r3 = p3.addNewTextRun();
+ r3.setText("Run Formatting");
+ r3.setFontSize(24d);
+ r3.setFontColor(new Color(85, 142, 213));
+
+ XSLFTextParagraph p4 = shape1.addNewTextParagraph();
+ p4.setSpaceBefore(-20d); // 20 pt from the previous paragraph
+ p4.setSpaceAfter(300d); // 3 lines after the paragraph
+ XSLFTextRun r4 = p4.addNewTextRun();
+ r4.setFontSize(16d);
+ r4.setText(
+ "Run level formatting is the most granular property level and allows " +
+ "for the specifying of all low level text properties. The text run is " +
+ "what all paragraphs are derived from and thus specifying various " +
+ "properties per run will allow for a diversely formatted text paragraph.");
+
+ // resize the shape to fit text
+ shape1.resizeToFitText();
+
+ try (FileOutputStream out = new FileOutputStream("text.pptx")) {
+ ppt.write(out);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xslf/Tutorial3.java b/poi-examples/src/main/java/org/apache/poi/examples/xslf/Tutorial3.java
new file mode 100644
index 0000000000..420605ee75
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xslf/Tutorial3.java
@@ -0,0 +1,51 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.xslf;
+
+import java.awt.Rectangle;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.sl.usermodel.Placeholder;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+import org.apache.poi.xslf.usermodel.XSLFTextShape;
+
+/**
+ * How to set slide title
+ */
+public final class Tutorial3 {
+ private Tutorial3() {}
+
+ public static void main(String[] args) throws IOException{
+ try (XMLSlideShow ppt = new XMLSlideShow()) {
+ XSLFSlide slide = ppt.createSlide();
+
+ XSLFTextShape titleShape = slide.createTextBox();
+ titleShape.setPlaceholder(Placeholder.TITLE);
+ titleShape.setText("This is a slide title");
+ titleShape.setAnchor(new Rectangle(50, 50, 400, 100));
+
+ try (FileOutputStream out = new FileOutputStream("title.pptx")) {
+ ppt.write(out);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xslf/Tutorial4.java b/poi-examples/src/main/java/org/apache/poi/examples/xslf/Tutorial4.java
new file mode 100644
index 0000000000..a39e9030d8
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xslf/Tutorial4.java
@@ -0,0 +1,96 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.xslf;
+
+import java.awt.Color;
+import java.awt.Rectangle;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.sl.usermodel.TableCell.BorderEdge;
+import org.apache.poi.sl.usermodel.TextParagraph.TextAlign;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+import org.apache.poi.xslf.usermodel.XSLFTable;
+import org.apache.poi.xslf.usermodel.XSLFTableCell;
+import org.apache.poi.xslf.usermodel.XSLFTableRow;
+import org.apache.poi.xslf.usermodel.XSLFTextParagraph;
+import org.apache.poi.xslf.usermodel.XSLFTextRun;
+
+/**
+ * PPTX Tables
+ */
+public final class Tutorial4 {
+ private Tutorial4() {}
+
+ public static void main(String[] args) throws IOException{
+ try (XMLSlideShow ppt = new XMLSlideShow()) {
+ // XSLFSlide#createSlide() with no arguments creates a blank slide
+ XSLFSlide slide = ppt.createSlide();
+
+ XSLFTable tbl = slide.createTable();
+ tbl.setAnchor(new Rectangle(50, 50, 450, 300));
+
+ int numColumns = 3;
+ int numRows = 5;
+ XSLFTableRow headerRow = tbl.addRow();
+ headerRow.setHeight(50);
+ // header
+ for (int i = 0; i < numColumns; i++) {
+ XSLFTableCell th = headerRow.addCell();
+ XSLFTextParagraph p = th.addNewTextParagraph();
+ p.setTextAlign(TextAlign.CENTER);
+ XSLFTextRun r = p.addNewTextRun();
+ r.setText("Header " + (i + 1));
+ r.setBold(true);
+ r.setFontColor(Color.white);
+ th.setFillColor(new Color(79, 129, 189));
+ th.setBorderWidth(BorderEdge.bottom, 2.0);
+ th.setBorderColor(BorderEdge.bottom, Color.white);
+
+ tbl.setColumnWidth(i, 150); // all columns are equally sized
+ }
+
+ // rows
+
+ for (int rownum = 0; rownum < numRows; rownum++) {
+ XSLFTableRow tr = tbl.addRow();
+ tr.setHeight(50);
+ // header
+ for (int i = 0; i < numColumns; i++) {
+ XSLFTableCell cell = tr.addCell();
+ XSLFTextParagraph p = cell.addNewTextParagraph();
+ XSLFTextRun r = p.addNewTextRun();
+
+ r.setText("Cell " + (i + 1));
+ if (rownum % 2 == 0)
+ cell.setFillColor(new Color(208, 216, 232));
+ else
+ cell.setFillColor(new Color(233, 247, 244));
+
+ }
+ }
+
+ try (FileOutputStream out = new FileOutputStream("table.pptx")) {
+ ppt.write(out);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xslf/Tutorial5.java b/poi-examples/src/main/java/org/apache/poi/examples/xslf/Tutorial5.java
new file mode 100644
index 0000000000..cc459a17bb
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xslf/Tutorial5.java
@@ -0,0 +1,52 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.xslf;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.sl.usermodel.PictureData.PictureType;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFPictureData;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+
+/**
+ * Images
+ */
+public final class Tutorial5 {
+ private Tutorial5() {}
+
+ public static void main(String[] args) throws IOException{
+ try (XMLSlideShow ppt = new XMLSlideShow()) {
+ XSLFSlide slide = ppt.createSlide();
+
+ File img = new File(System.getProperty("POI.testdata.path", "test-data"), "slideshow/clock.jpg");
+ XSLFPictureData pictureData = ppt.addPicture(img, PictureType.PNG);
+
+ /*XSLFPictureShape shape =*/
+ slide.createPicture(pictureData);
+
+ try (FileOutputStream out = new FileOutputStream("images.pptx")) {
+ ppt.write(out);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xslf/Tutorial6.java b/poi-examples/src/main/java/org/apache/poi/examples/xslf/Tutorial6.java
new file mode 100644
index 0000000000..1648e21acf
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xslf/Tutorial6.java
@@ -0,0 +1,63 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.xslf;
+
+import java.awt.Rectangle;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFHyperlink;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+import org.apache.poi.xslf.usermodel.XSLFTextBox;
+import org.apache.poi.xslf.usermodel.XSLFTextRun;
+
+/**
+ * Hyperlinks
+ */
+public final class Tutorial6 {
+ private Tutorial6() {}
+
+ public static void main(String[] args) throws IOException{
+ try (XMLSlideShow ppt = new XMLSlideShow()) {
+ XSLFSlide slide1 = ppt.createSlide();
+ XSLFSlide slide2 = ppt.createSlide();
+
+ XSLFTextBox shape1 = slide1.createTextBox();
+ shape1.setAnchor(new Rectangle(50, 50, 200, 50));
+ XSLFTextRun r1 = shape1.addNewTextParagraph().addNewTextRun();
+ XSLFHyperlink link1 = r1.createHyperlink();
+ r1.setText("https://poi.apache.org"); // visible text
+ link1.setAddress("https://poi.apache.org"); // link address
+
+ XSLFTextBox shape2 = slide1.createTextBox();
+ shape2.setAnchor(new Rectangle(300, 50, 200, 50));
+ XSLFTextRun r2 = shape2.addNewTextParagraph().addNewTextRun();
+ XSLFHyperlink link2 = r2.createHyperlink();
+ r2.setText("Go to the second slide"); // visible text
+ link2.linkToSlide(slide2); // link address
+
+
+ try (FileOutputStream out = new FileOutputStream("hyperlinks.pptx")) {
+ ppt.write(out);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xslf/Tutorial7.java b/poi-examples/src/main/java/org/apache/poi/examples/xslf/Tutorial7.java
new file mode 100644
index 0000000000..d617de8dbc
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xslf/Tutorial7.java
@@ -0,0 +1,92 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.xslf;
+
+import java.awt.Color;
+import java.awt.Rectangle;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.sl.usermodel.AutoNumberingScheme;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+import org.apache.poi.xslf.usermodel.XSLFTextBox;
+import org.apache.poi.xslf.usermodel.XSLFTextParagraph;
+import org.apache.poi.xslf.usermodel.XSLFTextRun;
+
+/**
+ * Bullets and numbering
+ */
+public final class Tutorial7 {
+ private Tutorial7() {}
+
+ public static void main(String[] args) throws IOException {
+ try (XMLSlideShow ppt = new XMLSlideShow()) {
+ XSLFSlide slide = ppt.createSlide();
+ XSLFTextBox shape = slide.createTextBox();
+ shape.setAnchor(new Rectangle(50, 50, 400, 200));
+
+ XSLFTextParagraph p1 = shape.addNewTextParagraph();
+ p1.setIndentLevel(0);
+ p1.setBullet(true);
+ XSLFTextRun r1 = p1.addNewTextRun();
+ r1.setText("Bullet1");
+
+ XSLFTextParagraph p2 = shape.addNewTextParagraph();
+ // indentation before text
+ p2.setLeftMargin(60d);
+ // the bullet is set 40 pt before the text
+ p2.setIndent(-40d);
+ p2.setBullet(true);
+ // customize bullets
+ p2.setBulletFontColor(Color.red);
+ p2.setBulletFont("Wingdings");
+ p2.setBulletCharacter("\u0075");
+ p2.setIndentLevel(1);
+ XSLFTextRun r2 = p2.addNewTextRun();
+ r2.setText("Bullet2");
+
+ // the next three paragraphs form an auto-numbered list
+ XSLFTextParagraph p3 = shape.addNewTextParagraph();
+ p3.setBulletAutoNumber(AutoNumberingScheme.alphaLcParenRight, 1);
+ p3.setIndentLevel(2);
+ XSLFTextRun r3 = p3.addNewTextRun();
+ r3.setText("Numbered List Item - 1");
+
+ XSLFTextParagraph p4 = shape.addNewTextParagraph();
+ p4.setBulletAutoNumber(AutoNumberingScheme.alphaLcParenRight, 2);
+ p4.setIndentLevel(2);
+ XSLFTextRun r4 = p4.addNewTextRun();
+ r4.setText("Numbered List Item - 2");
+
+ XSLFTextParagraph p5 = shape.addNewTextParagraph();
+ p5.setBulletAutoNumber(AutoNumberingScheme.alphaLcParenRight, 3);
+ p5.setIndentLevel(2);
+ XSLFTextRun r5 = p5.addNewTextRun();
+ r5.setText("Numbered List Item - 3");
+
+ shape.resizeToFitText();
+
+ try (FileOutputStream out = new FileOutputStream("list.pptx")) {
+ ppt.write(out);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xslf/bar-chart-data.txt b/poi-examples/src/main/java/org/apache/poi/examples/xslf/bar-chart-data.txt
new file mode 100644
index 0000000000..22c7b86ab8
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xslf/bar-chart-data.txt
@@ -0,0 +1,12 @@
+10 languages with most speakers as first language
+countries,speakers,language
+58,315,العربية
+4,243,বাংলা
+38,1299,中文
+118,378,English
+4,260,हिन्दी
+2,128,日本語
+15,223,português
+6,119,ਪੰਜਾਬੀ
+18,154,Русский язык
+31,442,español
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xslf/bar-chart-template.pptx b/poi-examples/src/main/java/org/apache/poi/examples/xslf/bar-chart-template.pptx
new file mode 100644
index 0000000000..e4d2613046
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xslf/bar-chart-template.pptx
Binary files differ
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xslf/pie-chart-data.txt b/poi-examples/src/main/java/org/apache/poi/examples/xslf/pie-chart-data.txt
new file mode 100644
index 0000000000..40b6959c2c
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xslf/pie-chart-data.txt
@@ -0,0 +1,4 @@
+My Chart
+First 1.0
+Second 3.0
+Third 4.0 \ No newline at end of file
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xslf/pie-chart-template.pptx b/poi-examples/src/main/java/org/apache/poi/examples/xslf/pie-chart-template.pptx
new file mode 100644
index 0000000000..33d28e154c
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xslf/pie-chart-template.pptx
Binary files differ
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xslf/tutorial/Step1.java b/poi-examples/src/main/java/org/apache/poi/examples/xslf/tutorial/Step1.java
new file mode 100644
index 0000000000..2d384a8389
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xslf/tutorial/Step1.java
@@ -0,0 +1,71 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.xslf.tutorial;
+
+import java.io.FileInputStream;
+
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFShape;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+import org.apache.poi.xslf.usermodel.XSLFTextParagraph;
+import org.apache.poi.xslf.usermodel.XSLFTextRun;
+import org.apache.poi.xslf.usermodel.XSLFTextShape;
+
+/**
+ * Reading a .pptx presentation and printing basic shape properties
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class Step1 {
+ private Step1() {}
+
+ public static void main(String[] args) throws Exception {
+ if(args.length == 0) {
+ System.out.println("Input file is required");
+ return;
+ }
+
+ FileInputStream fis = new FileInputStream(args[0]);
+ try (XMLSlideShow ppt = new XMLSlideShow(fis)) {
+ fis.close();
+
+ for (XSLFSlide slide : ppt.getSlides()) {
+ System.out.println("Title: " + slide.getTitle());
+
+ for (XSLFShape shape : slide.getShapes()) {
+ if (shape instanceof XSLFTextShape) {
+ XSLFTextShape tsh = (XSLFTextShape) shape;
+ for (XSLFTextParagraph p : tsh) {
+ System.out.println("Paragraph level: " + p.getIndentLevel());
+ for (XSLFTextRun r : p) {
+ System.out.println(r.getRawText());
+ System.out.println(" bold: " + r.isBold());
+ System.out.println(" italic: " + r.isItalic());
+ System.out.println(" underline: " + r.isUnderlined());
+ System.out.println(" font.family: " + r.getFontFamily());
+ System.out.println(" font.size: " + r.getFontSize());
+ System.out.println(" font.color: " + r.getFontColor());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xslf/tutorial/Step2.java b/poi-examples/src/main/java/org/apache/poi/examples/xslf/tutorial/Step2.java
new file mode 100644
index 0000000000..68fcf14f5c
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xslf/tutorial/Step2.java
@@ -0,0 +1,79 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.xslf.tutorial;
+
+import java.io.FileOutputStream;
+
+import org.apache.poi.xslf.usermodel.SlideLayout;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+import org.apache.poi.xslf.usermodel.XSLFSlideLayout;
+import org.apache.poi.xslf.usermodel.XSLFSlideMaster;
+import org.apache.poi.xslf.usermodel.XSLFTextShape;
+
+/**
+ * Create slides from pre-defined slide layouts
+ */
+public final class Step2 {
+ private Step2() {}
+
+ public static void main(String[] args) throws Exception{
+ try (XMLSlideShow ppt = new XMLSlideShow()) {
+
+ // first see what slide layouts are available by default
+ System.out.println("Available slide layouts:");
+ for (XSLFSlideMaster master : ppt.getSlideMasters()) {
+ for (XSLFSlideLayout layout : master.getSlideLayouts()) {
+ System.out.println(layout.getType());
+ }
+ }
+
+ // blank slide
+ /*XSLFSlide blankSlide =*/
+ ppt.createSlide();
+
+ XSLFSlideMaster defaultMaster = ppt.getSlideMasters().get(0);
+
+ // title slide
+ XSLFSlideLayout titleLayout = defaultMaster.getLayout(SlideLayout.TITLE);
+ XSLFSlide slide1 = ppt.createSlide(titleLayout);
+ XSLFTextShape title1 = slide1.getPlaceholder(0);
+ title1.setText("First Title");
+
+ // title and content
+ XSLFSlideLayout titleBodyLayout = defaultMaster.getLayout(SlideLayout.TITLE_AND_CONTENT);
+ XSLFSlide slide2 = ppt.createSlide(titleBodyLayout);
+
+ XSLFTextShape title2 = slide2.getPlaceholder(0);
+ title2.setText("Second Title");
+
+ XSLFTextShape body2 = slide2.getPlaceholder(1);
+ body2.clearText(); // unset any existing text
+ body2.addNewTextParagraph().addNewTextRun().setText("First paragraph");
+ body2.addNewTextParagraph().addNewTextRun().setText("Second paragraph");
+ body2.addNewTextParagraph().addNewTextRun().setText("Third paragraph");
+
+
+ try (FileOutputStream out = new FileOutputStream("step2.pptx")) {
+ ppt.write(out);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/eventusermodel/FromHowTo.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/eventusermodel/FromHowTo.java
new file mode 100644
index 0000000000..d61b4adb38
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/eventusermodel/FromHowTo.java
@@ -0,0 +1,163 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.xssf.eventusermodel;
+
+import java.io.InputStream;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.openxml4j.opc.PackageAccess;
+import org.apache.poi.util.XMLHelper;
+import org.apache.poi.xssf.eventusermodel.XSSFReader;
+import org.apache.poi.xssf.model.SharedStringsTable;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * XSSF and SAX (Event API) basic example.
+ * See {@link XLSX2CSV} for a fuller example of doing
+ * XSLX processing with the XSSF Event code.
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public class FromHowTo {
+ public void processFirstSheet(String filename) throws Exception {
+ try (OPCPackage pkg = OPCPackage.open(filename, PackageAccess.READ)) {
+ XSSFReader r = new XSSFReader(pkg);
+ SharedStringsTable sst = r.getSharedStringsTable();
+
+ XMLReader parser = fetchSheetParser(sst);
+
+ // process the first sheet
+ try (InputStream sheet = r.getSheetsData().next()) {
+ InputSource sheetSource = new InputSource(sheet);
+ parser.parse(sheetSource);
+ }
+ }
+ }
+
+ public void processAllSheets(String filename) throws Exception {
+ try (OPCPackage pkg = OPCPackage.open(filename, PackageAccess.READ)) {
+ XSSFReader r = new XSSFReader(pkg);
+ SharedStringsTable sst = r.getSharedStringsTable();
+
+ XMLReader parser = fetchSheetParser(sst);
+
+ Iterator<InputStream> sheets = r.getSheetsData();
+ while (sheets.hasNext()) {
+ System.out.println("Processing new sheet:\n");
+ try (InputStream sheet = sheets.next()) {
+ InputSource sheetSource = new InputSource(sheet);
+ parser.parse(sheetSource);
+ }
+ System.out.println();
+ }
+ }
+ }
+
+ public XMLReader fetchSheetParser(SharedStringsTable sst) throws SAXException, ParserConfigurationException {
+ XMLReader parser = XMLHelper.newXMLReader();
+ ContentHandler handler = new SheetHandler(sst);
+ parser.setContentHandler(handler);
+ return parser;
+ }
+
+ /**
+ * See org.xml.sax.helpers.DefaultHandler javadocs
+ */
+ private static class SheetHandler extends DefaultHandler {
+ private final SharedStringsTable sst;
+ private String lastContents;
+ private boolean nextIsString;
+ private boolean inlineStr;
+ private final LruCache<Integer,String> lruCache = new LruCache<>(50);
+
+ private static class LruCache<A,B> extends LinkedHashMap<A, B> {
+ private final int maxEntries;
+
+ public LruCache(final int maxEntries) {
+ super(maxEntries + 1, 1.0f, true);
+ this.maxEntries = maxEntries;
+ }
+
+ @Override
+ protected boolean removeEldestEntry(final Map.Entry<A, B> eldest) {
+ return super.size() > maxEntries;
+ }
+ }
+
+ private SheetHandler(SharedStringsTable sst) {
+ this.sst = sst;
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String name,
+ Attributes attributes) throws SAXException {
+ // c => cell
+ if(name.equals("c")) {
+ // Print the cell reference
+ System.out.print(attributes.getValue("r") + " - ");
+ // Figure out if the value is an index in the SST
+ String cellType = attributes.getValue("t");
+ nextIsString = cellType != null && cellType.equals("s");
+ inlineStr = cellType != null && cellType.equals("inlineStr");
+ }
+ // Clear contents cache
+ lastContents = "";
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String name)
+ throws SAXException {
+ // Process the last contents as required.
+ // Do now, as characters() may be called more than once
+ if(nextIsString && !lastContents.trim().isEmpty()) {
+ Integer idx = Integer.valueOf(lastContents);
+ lastContents = lruCache.get(idx);
+ if (lastContents == null && !lruCache.containsKey(idx)) {
+ lastContents = sst.getItemAt(idx).getString();
+ lruCache.put(idx, lastContents);
+ }
+ nextIsString = false;
+ }
+
+ // v => contents of a cell
+ // Output after we've seen the string contents
+ if(name.equals("v") || (inlineStr && name.equals("c"))) {
+ System.out.println(lastContents);
+ }
+ }
+
+ @Override
+ public void characters(char[] ch, int start, int length) throws SAXException { // NOSONAR
+ lastContents += new String(ch, start, length);
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ FromHowTo howto = new FromHowTo();
+ howto.processFirstSheet(args[0]);
+ howto.processAllSheets(args[0]);
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/eventusermodel/LoadPasswordProtectedXlsxStreaming.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/eventusermodel/LoadPasswordProtectedXlsxStreaming.java
new file mode 100644
index 0000000000..96ba25e396
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/eventusermodel/LoadPasswordProtectedXlsxStreaming.java
@@ -0,0 +1,60 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.xssf.eventusermodel;
+
+import java.io.InputStream;
+
+import org.apache.poi.examples.xssf.usermodel.LoadPasswordProtectedXlsx;
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.poifs.crypt.temp.AesZipFileZipEntrySource;
+import org.apache.poi.xssf.eventusermodel.XSSFReader;
+import org.apache.poi.xssf.eventusermodel.XSSFReader.SheetIterator;
+
+/**
+ * An example that loads a password protected workbook and counts the sheets.
+ * The example highlights how to do this in streaming way.
+ * <p><ul>
+ * <li>The example demonstrates that all temp files are removed.
+ * <li><code>AesZipFileZipEntrySource</code> is used to ensure that temp files are encrypted.
+ * </ul><p>
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class LoadPasswordProtectedXlsxStreaming {
+
+ private LoadPasswordProtectedXlsxStreaming() {}
+
+ public static void main(String[] args) throws Exception {
+ LoadPasswordProtectedXlsx.execute(args, LoadPasswordProtectedXlsxStreaming::printSheetCount);
+ }
+
+ private static void printSheetCount(final InputStream inputStream) throws Exception {
+ try (AesZipFileZipEntrySource source = AesZipFileZipEntrySource.createZipEntrySource(inputStream);
+ OPCPackage pkg = OPCPackage.open(source)) {
+ XSSFReader reader = new XSSFReader(pkg);
+ SheetIterator iter = (SheetIterator)reader.getSheetsData();
+ int count = 0;
+ while(iter.hasNext()) {
+ iter.next();
+ count++;
+ }
+ System.out.println("sheet count: " + count);
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/eventusermodel/XLSX2CSV.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/eventusermodel/XLSX2CSV.java
new file mode 100644
index 0000000000..a9772b00ba
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/eventusermodel/XLSX2CSV.java
@@ -0,0 +1,263 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.xssf.eventusermodel;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.openxml4j.opc.PackageAccess;
+import org.apache.poi.ss.usermodel.DataFormatter;
+import org.apache.poi.ss.util.CellAddress;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.util.XMLHelper;
+import org.apache.poi.xssf.eventusermodel.ReadOnlySharedStringsTable;
+import org.apache.poi.xssf.eventusermodel.XSSFReader;
+import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler;
+import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler.SheetContentsHandler;
+import org.apache.poi.xssf.extractor.XSSFEventBasedExcelExtractor;
+import org.apache.poi.xssf.model.SharedStrings;
+import org.apache.poi.xssf.model.Styles;
+import org.apache.poi.xssf.model.StylesTable;
+import org.apache.poi.xssf.usermodel.XSSFComment;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+
+/**
+ * A rudimentary XLSX -&gt; CSV processor modeled on the
+ * POI sample program XLS2CSVmra from the package
+ * org.apache.poi.hssf.eventusermodel.examples.
+ * As with the HSSF version, this tries to spot missing
+ * rows and cells, and output empty entries for them.
+ * <p>
+ * Data sheets are read using a SAX parser to keep the
+ * memory footprint relatively small, so this should be
+ * able to read enormous workbooks. The styles table and
+ * the shared-string table must be kept in memory. The
+ * standard POI styles table class is used, but a custom
+ * (read-only) class is used for the shared string table
+ * because the standard POI SharedStringsTable grows very
+ * quickly with the number of unique strings.
+ * <p>
+ * For a more advanced implementation of SAX event parsing
+ * of XLSX files, see {@link XSSFEventBasedExcelExtractor}
+ * and {@link XSSFSheetXMLHandler}. Note that for many cases,
+ * it may be possible to simply use those with a custom
+ * {@link SheetContentsHandler} and no SAX code needed of
+ * your own!
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public class XLSX2CSV {
+ /**
+ * Uses the XSSF Event SAX helpers to do most of the work
+ * of parsing the Sheet XML, and outputs the contents
+ * as a (basic) CSV.
+ */
+ private class SheetToCSV implements SheetContentsHandler {
+ private boolean firstCellOfRow;
+ private int currentRow = -1;
+ private int currentCol = -1;
+
+ private void outputMissingRows(int number) {
+ for (int i=0; i<number; i++) {
+ for (int j=0; j<minColumns; j++) {
+ output.append(',');
+ }
+ output.append('\n');
+ }
+ }
+
+ @Override
+ public void startRow(int rowNum) {
+ // If there were gaps, output the missing rows
+ outputMissingRows(rowNum-currentRow-1);
+ // Prepare for this row
+ firstCellOfRow = true;
+ currentRow = rowNum;
+ currentCol = -1;
+ }
+
+ @Override
+ public void endRow(int rowNum) {
+ // Ensure the minimum number of columns
+ for (int i=currentCol; i<minColumns; i++) {
+ output.append(',');
+ }
+ output.append('\n');
+ }
+
+ @Override
+ public void cell(String cellReference, String formattedValue,
+ XSSFComment comment) {
+ if (firstCellOfRow) {
+ firstCellOfRow = false;
+ } else {
+ output.append(',');
+ }
+
+ // gracefully handle missing CellRef here in a similar way as XSSFCell does
+ if(cellReference == null) {
+ cellReference = new CellAddress(currentRow, currentCol).formatAsString();
+ }
+
+ // Did we miss any cells?
+ int thisCol = (new CellReference(cellReference)).getCol();
+ int missedCols = thisCol - currentCol - 1;
+ for (int i=0; i<missedCols; i++) {
+ output.append(',');
+ }
+
+ // no need to append anything if we do not have a value
+ if (formattedValue == null) {
+ return;
+ }
+
+ currentCol = thisCol;
+
+ // Number or string?
+ try {
+ //noinspection ResultOfMethodCallIgnored
+ Double.parseDouble(formattedValue);
+ output.append(formattedValue);
+ } catch (Exception e) {
+ // let's remove quotes if they are already there
+ if (formattedValue.startsWith("\"") && formattedValue.endsWith("\"")) {
+ formattedValue = formattedValue.substring(1, formattedValue.length()-1);
+ }
+
+ output.append('"');
+ // encode double-quote with two double-quotes to produce a valid CSV format
+ output.append(formattedValue.replace("\"", "\"\""));
+ output.append('"');
+ }
+ }
+ }
+
+
+ ///////////////////////////////////////
+
+ private final OPCPackage xlsxPackage;
+
+ /**
+ * Number of columns to read starting with leftmost
+ */
+ private final int minColumns;
+
+ /**
+ * Destination for data
+ */
+ private final PrintStream output;
+
+ /**
+ * Creates a new XLSX -&gt; CSV examples
+ *
+ * @param pkg The XLSX package to process
+ * @param output The PrintStream to output the CSV to
+ * @param minColumns The minimum number of columns to output, or -1 for no minimum
+ */
+ public XLSX2CSV(OPCPackage pkg, PrintStream output, int minColumns) {
+ this.xlsxPackage = pkg;
+ this.output = output;
+ this.minColumns = minColumns;
+ }
+
+ /**
+ * Parses and shows the content of one sheet
+ * using the specified styles and shared-strings tables.
+ *
+ * @param styles The table of styles that may be referenced by cells in the sheet
+ * @param strings The table of strings that may be referenced by cells in the sheet
+ * @param sheetInputStream The stream to read the sheet-data from.
+
+ * @exception java.io.IOException An IO exception from the parser,
+ * possibly from a byte stream or character stream
+ * supplied by the application.
+ * @throws SAXException if parsing the XML data fails.
+ */
+ public void processSheet(
+ Styles styles,
+ SharedStrings strings,
+ SheetContentsHandler sheetHandler,
+ InputStream sheetInputStream) throws IOException, SAXException {
+ DataFormatter formatter = new DataFormatter();
+ InputSource sheetSource = new InputSource(sheetInputStream);
+ try {
+ XMLReader sheetParser = XMLHelper.newXMLReader();
+ ContentHandler handler = new XSSFSheetXMLHandler(
+ styles, null, strings, sheetHandler, formatter, false);
+ sheetParser.setContentHandler(handler);
+ sheetParser.parse(sheetSource);
+ } catch(ParserConfigurationException e) {
+ throw new RuntimeException("SAX parser appears to be broken - " + e.getMessage());
+ }
+ }
+
+ /**
+ * Initiates the processing of the XLS workbook file to CSV.
+ *
+ * @throws IOException If reading the data from the package fails.
+ * @throws SAXException if parsing the XML data fails.
+ */
+ public void process() throws IOException, OpenXML4JException, SAXException {
+ ReadOnlySharedStringsTable strings = new ReadOnlySharedStringsTable(this.xlsxPackage);
+ XSSFReader xssfReader = new XSSFReader(this.xlsxPackage);
+ StylesTable styles = xssfReader.getStylesTable();
+ XSSFReader.SheetIterator iter = (XSSFReader.SheetIterator) xssfReader.getSheetsData();
+ int index = 0;
+ while (iter.hasNext()) {
+ try (InputStream stream = iter.next()) {
+ String sheetName = iter.getSheetName();
+ this.output.println();
+ this.output.println(sheetName + " [index=" + index + "]:");
+ processSheet(styles, strings, new SheetToCSV(), stream);
+ }
+ ++index;
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ if (args.length < 1) {
+ System.err.println("Use:");
+ System.err.println(" XLSX2CSV <xlsx file> [min columns]");
+ return;
+ }
+
+ File xlsxFile = new File(args[0]);
+ if (!xlsxFile.exists()) {
+ System.err.println("Not found or not a file: " + xlsxFile.getPath());
+ return;
+ }
+
+ int minColumns = -1;
+ if (args.length >= 2)
+ minColumns = Integer.parseInt(args[1]);
+
+ // The package open is instantaneous, as it should be.
+ try (OPCPackage p = OPCPackage.open(xlsxFile.getPath(), PackageAccess.READ)) {
+ XLSX2CSV xlsx2csv = new XLSX2CSV(p, System.out, minColumns);
+ xlsx2csv.process();
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/streaming/DeferredGeneration.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/streaming/DeferredGeneration.java
new file mode 100644
index 0000000000..9c53c4ee0b
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/streaming/DeferredGeneration.java
@@ -0,0 +1,54 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.xssf.streaming;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.xssf.streaming.DeferredSXSSFSheet;
+import org.apache.poi.xssf.streaming.DeferredSXSSFWorkbook;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * This sample demonstrates how to use DeferredSXSSFWorkbook to generate workbooks in a streaming way.
+ * This approach avoids the use of temporary files and can be used to output to streams like
+ * HTTP response streams.
+ */
+public class DeferredGeneration {
+
+ public static void main(String[] args) throws IOException {
+ try (DeferredSXSSFWorkbook wb = new DeferredSXSSFWorkbook()) {
+ DeferredSXSSFSheet sheet1 = wb.createSheet("new sheet");
+
+ sheet1.setRowGenerator((ssxSheet) -> {
+ for (int i = 0; i < 10; i++) {
+ Row row = ssxSheet.createRow(i);
+ Cell cell = row.createCell(1);
+ cell.setCellValue("value " + i);
+ }
+ });
+
+ try (FileOutputStream fileOut = new FileOutputStream("DeferredGeneration.xlsx")) {
+ wb.write(fileOut);
+ } finally {
+ wb.dispose();
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/streaming/HybridStreaming.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/streaming/HybridStreaming.java
new file mode 100644
index 0000000000..f131e5b6e8
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/streaming/HybridStreaming.java
@@ -0,0 +1,78 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.xssf.streaming;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.poi.xssf.eventusermodel.ReadOnlySharedStringsTable;
+import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler;
+import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler.SheetContentsHandler;
+import org.apache.poi.xssf.usermodel.XSSFComment;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheet;
+import org.xml.sax.SAXException;
+
+/**
+ * This demonstrates how a hybrid approach to workbook read can be taken, using
+ * a mix of traditional XSSF and streaming one particular worksheet (perhaps one
+ * which is too big for the ordinary DOM parse).
+ */
+public class HybridStreaming {
+
+ private static final String SHEET_TO_STREAM = "large sheet";
+
+ public static void main(String[] args) throws IOException, SAXException {
+ try (InputStream sourceBytes = new FileInputStream("workbook.xlsx")) {
+ XSSFWorkbook workbook = new XSSFWorkbook(sourceBytes) {
+ /**
+ * Avoid DOM parse of large sheet
+ */
+ @Override
+ public void parseSheet(java.util.Map<String, XSSFSheet> shIdMap, CTSheet ctSheet) {
+ if (!SHEET_TO_STREAM.equals(ctSheet.getName())) {
+ super.parseSheet(shIdMap, ctSheet);
+ }
+ }
+ };
+
+ // Having avoided a DOM-based parse of the sheet, we can stream it instead.
+ ReadOnlySharedStringsTable strings = new ReadOnlySharedStringsTable(workbook.getPackage());
+ new XSSFSheetXMLHandler(workbook.getStylesSource(), strings, createSheetContentsHandler(), false);
+ workbook.close();
+ }
+ }
+
+ private static SheetContentsHandler createSheetContentsHandler() {
+ return new SheetContentsHandler() {
+
+ @Override
+ public void startRow(int rowNum) {
+ }
+
+ @Override
+ public void endRow(int rowNum) {
+ }
+
+ @Override
+ public void cell(String cellReference, String formattedValue, XSSFComment comment) {
+ }
+ };
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/streaming/Outlining.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/streaming/Outlining.java
new file mode 100644
index 0000000000..6c29813edd
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/streaming/Outlining.java
@@ -0,0 +1,54 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.xssf.streaming;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.xssf.streaming.SXSSFSheet;
+import org.apache.poi.xssf.streaming.SXSSFWorkbook;
+
+public class Outlining {
+
+ public static void main(String[] args) throws IOException {
+ Outlining o = new Outlining();
+ o.collapseRow();
+ }
+
+ private void collapseRow() throws IOException {
+ try (SXSSFWorkbook wb2 = new SXSSFWorkbook(100)) {
+ SXSSFSheet sheet2 = wb2.createSheet("new sheet");
+
+ int rowCount = 20;
+ for (int i = 0; i < rowCount; i++) {
+ sheet2.createRow(i);
+ }
+
+ sheet2.groupRow(4, 9);
+ sheet2.groupRow(11, 19);
+
+ sheet2.setRowGroupCollapsed(4, true);
+
+ try (FileOutputStream fileOut = new FileOutputStream("outlining_collapsed.xlsx")) {
+ wb2.write(fileOut);
+ } finally {
+ wb2.dispose();
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/streaming/SavePasswordProtectedXlsx.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/streaming/SavePasswordProtectedXlsx.java
new file mode 100644
index 0000000000..f991047db7
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/streaming/SavePasswordProtectedXlsx.java
@@ -0,0 +1,104 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.xssf.streaming;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.GeneralSecurityException;
+
+import org.apache.poi.examples.util.TempFileUtils;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.poifs.crypt.EncryptionInfo;
+import org.apache.poi.poifs.crypt.EncryptionMode;
+import org.apache.poi.poifs.crypt.Encryptor;
+import org.apache.poi.poifs.crypt.temp.EncryptedTempData;
+import org.apache.poi.poifs.crypt.temp.SXSSFWorkbookWithCustomZipEntrySource;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.xssf.streaming.SXSSFCell;
+import org.apache.poi.xssf.streaming.SXSSFRow;
+import org.apache.poi.xssf.streaming.SXSSFSheet;
+
+/**
+ * An example that outputs a simple generated workbook that is password protected.
+ * The example highlights how to do this in streaming way.
+ * <p><ul>
+ * <li>The example demonstrates that all temp files are removed.
+ * <li><code>SXSSFWorkbookWithCustomZipEntrySource</code> extends SXSSFWorkbook to ensure temp files are encrypted.
+ * </ul><p>
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class SavePasswordProtectedXlsx {
+
+ private SavePasswordProtectedXlsx() {}
+
+ public static void main(String[] args) throws Exception {
+ if(args.length != 2) {
+ throw new IllegalArgumentException("Expected 2 params: filename and password");
+ }
+ TempFileUtils.checkTempFiles();
+ String filename = args[0];
+ String password = args[1];
+ SXSSFWorkbookWithCustomZipEntrySource wb = new SXSSFWorkbookWithCustomZipEntrySource();
+ try {
+ for(int i = 0; i < 10; i++) {
+ SXSSFSheet sheet = wb.createSheet("Sheet" + i);
+ for(int r = 0; r < 1000; r++) {
+ SXSSFRow row = sheet.createRow(r);
+ for(int c = 0; c < 100; c++) {
+ SXSSFCell cell = row.createCell(c);
+ cell.setCellValue("abcd");
+ }
+ }
+ }
+ EncryptedTempData tempData = new EncryptedTempData();
+ try {
+ wb.write(tempData.getOutputStream());
+ save(tempData.getInputStream(), filename, password);
+ System.out.println("Saved " + filename);
+ } finally {
+ tempData.dispose();
+ }
+ } finally {
+ wb.close();
+ wb.dispose();
+ }
+ TempFileUtils.checkTempFiles();
+ }
+
+ public static void save(final InputStream inputStream, final String filename, final String pwd)
+ throws InvalidFormatException, IOException, GeneralSecurityException {
+
+ try (POIFSFileSystem fs = new POIFSFileSystem();
+ OPCPackage opc = OPCPackage.open(inputStream);
+ FileOutputStream fos = new FileOutputStream(filename)) {
+ EncryptionInfo info = new EncryptionInfo(EncryptionMode.agile);
+ Encryptor enc = Encryptor.getInstance(info);
+ enc.confirmPassword(pwd);
+ opc.save(enc.getDataStream(fs));
+ fs.writeFilesystem(fos);
+ } finally {
+ IOUtils.closeQuietly(inputStream);
+ }
+ }
+
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/AligningCells.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/AligningCells.java
new file mode 100644
index 0000000000..17a92d3d8c
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/AligningCells.java
@@ -0,0 +1,139 @@
+/* ====================================================================
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.CreationHelper;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.VerticalAlignment;
+import org.apache.poi.xssf.usermodel.XSSFCell;
+import org.apache.poi.xssf.usermodel.XSSFCellStyle;
+import org.apache.poi.xssf.usermodel.XSSFRow;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTRowImpl;
+
+/**
+ * Shows how various alignment options work.
+ *
+ * Modified by Cristian Petrula, Romania on May 26, 2010
+ * New method was added centerAcrossSelection to center a column content over
+ * one selection using {@link HorizontalAlignment#CENTER_SELECTION}
+ * To create this method example was change for XSSF only and the previous
+ * AligningCells.java example has been moved into the SS examples folder.
+ */
+public class AligningCells {
+
+ public static void main(String[] args) throws IOException {
+ try (XSSFWorkbook wb = new XSSFWorkbook()) {
+
+ XSSFSheet sheet = wb.createSheet();
+ XSSFRow row = sheet.createRow(2);
+ row.setHeightInPoints(30);
+ for (int i = 0; i < 8; i++) {
+ //column width is set in units of 1/256th of a character width
+ sheet.setColumnWidth(i, 256 * 15);
+ }
+
+ createCell(wb, row, 0, HorizontalAlignment.CENTER, VerticalAlignment.BOTTOM);
+ createCell(wb, row, 1, HorizontalAlignment.CENTER_SELECTION, VerticalAlignment.BOTTOM);
+ createCell(wb, row, 2, HorizontalAlignment.FILL, VerticalAlignment.CENTER);
+ createCell(wb, row, 3, HorizontalAlignment.GENERAL, VerticalAlignment.CENTER);
+ createCell(wb, row, 4, HorizontalAlignment.JUSTIFY, VerticalAlignment.JUSTIFY);
+ createCell(wb, row, 5, HorizontalAlignment.LEFT, VerticalAlignment.TOP);
+ createCell(wb, row, 6, HorizontalAlignment.RIGHT, VerticalAlignment.TOP);
+
+ //center text over B4, C4, D4
+ row = sheet.createRow(3);
+ centerAcrossSelection(wb, row, 1, 3, VerticalAlignment.CENTER);
+
+ // Write the output to a file
+ try (OutputStream fileOut = new FileOutputStream("xssf-align.xlsx")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+
+ /**
+ * Creates a cell and aligns it a certain way.
+ *
+ * @param wb the workbook
+ * @param row the row to create the cell in
+ * @param column the column number to create the cell in
+ * @param halign the horizontal alignment for the cell.
+ */
+ private static void createCell(XSSFWorkbook wb, XSSFRow row, int column,
+ HorizontalAlignment halign, VerticalAlignment valign) {
+ CreationHelper ch = wb.getCreationHelper();
+ XSSFCell cell = row.createCell(column);
+ cell.setCellValue(ch.createRichTextString("Align It"));
+ CellStyle cellStyle = wb.createCellStyle();
+ cellStyle.setAlignment(halign);
+ cellStyle.setVerticalAlignment(valign);
+ cell.setCellStyle(cellStyle);
+ }
+
+ /**
+ * Center a text over multiple columns using ALIGN_CENTER_SELECTION
+ *
+ * @param wb the workbook
+ * @param row the row to create the cell in
+ * @param start_column the column number to create the cell in and where the selection starts
+ * @param end_column the column number where the selection ends
+ * @param valign the horizontal alignment for the cell.
+ */
+ private static void centerAcrossSelection(XSSFWorkbook wb, XSSFRow row,
+ int start_column, int end_column, VerticalAlignment valign) {
+ CreationHelper ch = wb.getCreationHelper();
+
+ // Create cell style with ALIGN_CENTER_SELECTION
+ XSSFCellStyle cellStyle = wb.createCellStyle();
+ cellStyle.setAlignment(HorizontalAlignment.CENTER_SELECTION);
+ cellStyle.setVerticalAlignment(valign);
+
+ // Create cells over the selected area
+ for (int i = start_column; i <= end_column; i++) {
+ XSSFCell cell = row.createCell(i);
+ cell.setCellStyle(cellStyle);
+ }
+
+ // Set value to the first cell
+ XSSFCell cell = row.getCell(start_column);
+ cell.setCellValue(ch.createRichTextString("Align It"));
+
+ // Make the selection
+ CTRowImpl ctRow = (CTRowImpl) row.getCTRow();
+
+ // Add object with format start_coll:end_coll. For example 1:3 will span from
+ // cell 1 to cell 3, where the column index starts with 0
+ //
+ // You can add multiple spans for one row
+ Object span = start_column + ":" + end_column;
+
+ List<Object> spanList = new ArrayList<>();
+ spanList.add(span);
+
+ //add spns to the row
+ ctRow.setSpans(spanList);
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/BarAndLineChart.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/BarAndLineChart.java
new file mode 100644
index 0000000000..32329f2c29
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/BarAndLineChart.java
@@ -0,0 +1,194 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.util.Random;
+
+import org.apache.poi.common.usermodel.fonts.FontGroup;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.xddf.usermodel.PresetColor;
+import org.apache.poi.xddf.usermodel.XDDFColor;
+import org.apache.poi.xddf.usermodel.XDDFFillProperties;
+import org.apache.poi.xddf.usermodel.XDDFLineProperties;
+import org.apache.poi.xddf.usermodel.XDDFSolidFillProperties;
+import org.apache.poi.xddf.usermodel.chart.AxisCrosses;
+import org.apache.poi.xddf.usermodel.chart.AxisPosition;
+import org.apache.poi.xddf.usermodel.chart.BarDirection;
+import org.apache.poi.xddf.usermodel.chart.ChartTypes;
+import org.apache.poi.xddf.usermodel.chart.LayoutMode;
+import org.apache.poi.xddf.usermodel.chart.LegendPosition;
+import org.apache.poi.xddf.usermodel.chart.MarkerStyle;
+import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFCategoryAxis;
+import org.apache.poi.xddf.usermodel.chart.XDDFCategoryDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
+import org.apache.poi.xddf.usermodel.chart.XDDFLineChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFManualLayout;
+import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
+import org.apache.poi.xddf.usermodel.text.UnderlineType;
+import org.apache.poi.xddf.usermodel.text.XDDFFont;
+import org.apache.poi.xddf.usermodel.text.XDDFRunProperties;
+import org.apache.poi.xddf.usermodel.text.XDDFTextParagraph;
+import org.apache.poi.xssf.usermodel.XSSFCell;
+import org.apache.poi.xssf.usermodel.XSSFChart;
+import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
+import org.apache.poi.xssf.usermodel.XSSFDrawing;
+import org.apache.poi.xssf.usermodel.XSSFRow;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+// original contributions by Axel Richter on https://stackoverflow.com/questions/47065690
+// additional title formatting from https://stackoverflow.com/questions/50418856
+// and legend positioning from https://stackoverflow.com/questions/49615379
+// this would probably be an answer for https://stackoverflow.com/questions/36447925 too
+public final class BarAndLineChart {
+
+ private static final int NUM_OF_ROWS = 7;
+ private static final Random RNG = new Random();
+
+ private BarAndLineChart() {}
+
+ public static void main(String[] args) throws Exception {
+ try (XSSFWorkbook wb = new XSSFWorkbook()) {
+ XSSFSheet sheet = wb.createSheet("Sheet1");
+
+ XSSFRow row = sheet.createRow(0);
+ row.createCell(0);
+ row.createCell(1).setCellValue("Bars");
+ row.createCell(2).setCellValue("Lines");
+
+ XSSFCell cell;
+ for (int r = 1; r < NUM_OF_ROWS; r++) {
+ row = sheet.createRow(r);
+ cell = row.createCell(0);
+ cell.setCellValue("C" + r);
+ cell = row.createCell(1);
+ cell.setCellValue(RNG.nextDouble());
+ cell = row.createCell(2);
+ cell.setCellValue(RNG.nextDouble() * 10);
+ }
+
+ XSSFDrawing drawing = sheet.createDrawingPatriarch();
+ XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 4, 0, 11, 15);
+
+ XSSFChart chart = drawing.createChart(anchor);
+ chart.setTitleText("This is my title");
+ chart.setTitleOverlay(true);
+ XDDFRunProperties properties = new XDDFRunProperties();
+ properties.setBold(true);
+ properties.setItalic(true);
+ properties.setUnderline(UnderlineType.DOT_DOT_DASH_HEAVY);
+ properties.setFontSize(22.5);
+ XDDFFont[] fonts = new XDDFFont[] {
+ new XDDFFont(FontGroup.LATIN, "Calibri", null, null, null),
+ new XDDFFont(FontGroup.COMPLEX_SCRIPT, "Liberation Sans", null, null, null)
+ };
+ properties.setFonts(fonts);
+ properties.setLineProperties(new XDDFLineProperties(
+ new XDDFSolidFillProperties(XDDFColor.from(PresetColor.SIENNA))));
+ XDDFTextParagraph paragraph = chart.getTitle().getBody().getParagraph(0);
+ paragraph.setDefaultRunProperties(properties);
+
+ // the data sources
+ XDDFCategoryDataSource xs = XDDFDataSourcesFactory.fromStringCellRange(sheet,
+ new CellRangeAddress(1, NUM_OF_ROWS - 1, 0, 0));
+ XDDFNumericalDataSource<Double> ys1 = XDDFDataSourcesFactory.fromNumericCellRange(sheet,
+ new CellRangeAddress(1, NUM_OF_ROWS - 1, 1, 1));
+ XDDFNumericalDataSource<Double> ys2 = XDDFDataSourcesFactory.fromNumericCellRange(sheet,
+ new CellRangeAddress(1, NUM_OF_ROWS - 1, 2, 2));
+
+ // cat axis 1 (bars)
+ XDDFCategoryAxis barCategories = chart.createCategoryAxis(AxisPosition.BOTTOM);
+
+ // val axis 1 (left)
+ XDDFValueAxis leftValues = chart.createValueAxis(AxisPosition.LEFT);
+ leftValues.crossAxis(barCategories);
+ barCategories.crossAxis(leftValues);
+
+ // cat axis 2 (lines)
+ XDDFCategoryAxis lineCategories = chart.createCategoryAxis(AxisPosition.BOTTOM);
+ lineCategories.setVisible(false); // this cat axis is deleted
+
+ // val axis 2 (right)
+ XDDFValueAxis rightValues = chart.createValueAxis(AxisPosition.RIGHT);
+ // this value axis crosses its category axis at max value
+ rightValues.setCrosses(AxisCrosses.MAX);
+ rightValues.crossAxis(lineCategories);
+ lineCategories.crossAxis(rightValues);
+
+ // the bar chart
+ XDDFBarChartData bar = (XDDFBarChartData) chart.createData(ChartTypes.BAR, barCategories, leftValues);
+ XDDFBarChartData.Series series1 = (XDDFBarChartData.Series) bar.addSeries(xs, ys1);
+ series1.setTitle(null, new CellReference(sheet.getSheetName(), 0, 1, true,true));
+ bar.setVaryColors(true);
+ bar.setBarDirection(BarDirection.COL);
+ chart.plot(bar);
+
+ // the line chart on secondary axis
+ XDDFLineChartData lines = (XDDFLineChartData) chart.createData(ChartTypes.LINE, lineCategories,
+ rightValues);
+
+ //uncomment below line if only primary axis required and comment above line
+ // the line chart on primary axis
+ /*XDDFLineChartData lines = (XDDFLineChartData) chart.createData(ChartTypes.LINE, lineCategories,
+ leftValues);*/
+
+
+ XDDFLineChartData.Series series2 = (XDDFLineChartData.Series) lines.addSeries(xs, ys2);
+ series2.setTitle(null, new CellReference(sheet.getSheetName(), 0, 2, true, true));
+ series2.setSmooth(false);
+ series2.setMarkerStyle(MarkerStyle.DIAMOND);
+ series2.setMarkerSize((short)14);
+ lines.setVaryColors(true);
+ chart.plot(lines);
+
+ // some colors
+ XDDFFillProperties solidChartreuse = new XDDFSolidFillProperties(XDDFColor.from(PresetColor.CHARTREUSE));
+ XDDFFillProperties solidTurquoise = new XDDFSolidFillProperties(XDDFColor.from(PresetColor.TURQUOISE));
+ XDDFLineProperties linesChartreuse = new XDDFLineProperties(solidChartreuse);
+ XDDFLineProperties linesTurquoise = new XDDFLineProperties(solidTurquoise);
+ series1.setFillProperties(solidChartreuse);
+ series1.setLineProperties(linesTurquoise); // bar border color different from fill
+ series1.getDataPoint(2).setFillProperties(solidTurquoise); // this specific bar has inverted colors
+ series1.getDataPoint(2).setLineProperties(linesChartreuse);
+ series2.setLineProperties(linesTurquoise);
+ series2.getDataPoint(2).setMarkerStyle(MarkerStyle.STAR);
+ series2.getDataPoint(2).setLineProperties(linesChartreuse);
+
+ // legend
+ XDDFChartLegend legend = chart.getOrAddLegend();
+ legend.setPosition(LegendPosition.LEFT);
+ legend.setOverlay(false);
+ XDDFManualLayout layout = legend.getOrAddManualLayout();
+ layout.setXMode(LayoutMode.EDGE);
+ layout.setYMode(LayoutMode.EDGE);
+ layout.setX(0.00); //left edge of the chart
+ layout.setY(0.25); //25% of chart's height from top edge of the chart
+
+ try (FileOutputStream fileOut = new FileOutputStream("BarAndLineChart.xlsx")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/BarChart.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/BarChart.java
new file mode 100644
index 0000000000..8c68fe87a7
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/BarChart.java
@@ -0,0 +1,124 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xddf.usermodel.PresetColor;
+import org.apache.poi.xddf.usermodel.XDDFColor;
+import org.apache.poi.xddf.usermodel.XDDFShapeProperties;
+import org.apache.poi.xddf.usermodel.XDDFSolidFillProperties;
+import org.apache.poi.xddf.usermodel.chart.AxisCrosses;
+import org.apache.poi.xddf.usermodel.chart.AxisPosition;
+import org.apache.poi.xddf.usermodel.chart.BarDirection;
+import org.apache.poi.xddf.usermodel.chart.ChartTypes;
+import org.apache.poi.xddf.usermodel.chart.LegendPosition;
+import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFCategoryAxis;
+import org.apache.poi.xddf.usermodel.chart.XDDFChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
+import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
+import org.apache.poi.xssf.usermodel.XSSFChart;
+import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
+import org.apache.poi.xssf.usermodel.XSSFDrawing;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Line chart example.
+ */
+public final class BarChart {
+ private BarChart() {}
+
+ public static void main(String[] args) throws IOException {
+ try (XSSFWorkbook wb = new XSSFWorkbook()) {
+ XSSFSheet sheet = wb.createSheet("barchart");
+ final int NUM_OF_ROWS = 3;
+ final int NUM_OF_COLUMNS = 10;
+
+ // Create a row and put some cells in it. Rows are 0 based.
+ Row row;
+ Cell cell;
+ for (int rowIndex = 0; rowIndex < NUM_OF_ROWS; rowIndex++) {
+ row = sheet.createRow((short) rowIndex);
+ for (int colIndex = 0; colIndex < NUM_OF_COLUMNS; colIndex++) {
+ cell = row.createCell((short) colIndex);
+ cell.setCellValue(colIndex * (rowIndex + 1.0));
+ }
+ }
+
+ XSSFDrawing drawing = sheet.createDrawingPatriarch();
+ XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 5, 10, 15);
+
+ XSSFChart chart = drawing.createChart(anchor);
+ chart.setTitleText("x = 2x and x = 3x");
+ chart.setTitleOverlay(false);
+ XDDFChartLegend legend = chart.getOrAddLegend();
+ legend.setPosition(LegendPosition.TOP_RIGHT);
+
+ // Use a category axis for the bottom axis.
+ XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
+ bottomAxis.setTitle("x"); // https://stackoverflow.com/questions/32010765
+ XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
+ leftAxis.setTitle("f(x)");
+ leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
+
+ XDDFDataSource<Double> xs = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(0, 0, 0, NUM_OF_COLUMNS - 1));
+ XDDFNumericalDataSource<Double> ys1 = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(1, 1, 0, NUM_OF_COLUMNS - 1));
+ XDDFNumericalDataSource<Double> ys2 = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(2, 2, 0, NUM_OF_COLUMNS - 1));
+
+ XDDFChartData data = chart.createData(ChartTypes.BAR, bottomAxis, leftAxis);
+ XDDFChartData.Series series1 = data.addSeries(xs, ys1);
+ series1.setTitle("2x", null); // https://stackoverflow.com/questions/21855842
+ XDDFChartData.Series series2 = data.addSeries(xs, ys2);
+ series2.setTitle("3x", null);
+ chart.plot(data);
+
+ // in order to transform a bar chart into a column chart, you just need to change the bar direction
+ XDDFBarChartData bar = (XDDFBarChartData) data;
+ bar.setBarDirection(BarDirection.COL);
+ // looking for "Stacked Bar Chart"? uncomment the following line
+ // bar.setBarGrouping(BarGrouping.STACKED);
+
+ solidFillSeries(data, 0, PresetColor.CHARTREUSE);
+ solidFillSeries(data, 1, PresetColor.TURQUOISE);
+
+ // Write the output to a file
+ try (FileOutputStream fileOut = new FileOutputStream("ooxml-bar-chart.xlsx")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+
+ private static void solidFillSeries(XDDFChartData data, int index, PresetColor color) {
+ XDDFSolidFillProperties fill = new XDDFSolidFillProperties(XDDFColor.from(color));
+ XDDFChartData.Series series = data.getSeries(index);
+ XDDFShapeProperties properties = series.getShapeProperties();
+ if (properties == null) {
+ properties = new XDDFShapeProperties();
+ }
+ properties.setFillProperties(fill);
+ series.setShapeProperties(properties);
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/BigGridDemo.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/BigGridDemo.java
new file mode 100644
index 0000000000..574458f7be
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/BigGridDemo.java
@@ -0,0 +1,304 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.util.Calendar;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+
+import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
+import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
+import org.apache.commons.compress.archivers.zip.ZipFile;
+import org.apache.poi.openxml4j.opc.internal.ZipHelper;
+import org.apache.poi.ss.usermodel.DateUtil;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.util.LocaleUtil;
+import org.apache.poi.xssf.usermodel.XSSFCellStyle;
+import org.apache.poi.xssf.usermodel.XSSFDataFormat;
+import org.apache.poi.xssf.usermodel.XSSFFont;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Demonstrates a workaround you can use to generate large workbooks and avoid OutOfMemory exception.
+ *
+ * Note - You probably <em>don't want to use this approach any more</em>! POI
+ * now includes the SXSSF which handles all of this for you, you should
+ * be using that instead! This code remains mostly for historical interest.
+ * <p>
+ * See <a "https://poi.apache.org/spreadsheet/how-to.html#sxssf">
+ * https://poi.apache.org/spreadsheet/how-to.html#sxssf</a>.
+ * <p>
+ * If you really want to use this approach, which is also the one that SXSSF
+ * does for you, it works as follows:
+ *
+ * 1. create a template workbook, create sheets and global objects such as cell styles, number formats, etc.
+ * 2. create an application that streams data in a text file
+ * 3. Substitute the sheet in the template with the generated data
+ *
+ * <p>
+ * Since 3.8 POI provides a low-memory footprint SXSSF API, which implements
+ * ths "BigGridDemo" strategy. SXSSF is an API-compatible streaming extension
+ * of XSSF to be used when very large spreadsheets have to be produced, and
+ * heap space is limited. SXSSF achieves its low memory footprint by limiting
+ * access to the rows that are within a sliding window, while XSSF gives access
+ * to all rows in the document. Older rows that are no longer in the window
+ * become inaccessible, as they are written to the disk.
+ * </p>
+ * See <a "https://poi.apache.org/spreadsheet/how-to.html#sxssf">
+ * https://poi.apache.org/spreadsheet/how-to.html#sxssf</a>.
+ */
+public final class BigGridDemo {
+ private static final String XML_ENCODING = "UTF-8";
+
+ private static final Random rnd = new Random();
+
+ private BigGridDemo() {}
+
+ public static void main(String[] args) throws Exception {
+
+ // Step 1. Create a template file. Setup sheets and workbook-level objects such as
+ // cell styles, number formats, etc.
+
+ try (XSSFWorkbook wb = new XSSFWorkbook()) {
+ XSSFSheet sheet = wb.createSheet("Big Grid");
+
+ Map<String, XSSFCellStyle> styles = createStyles(wb);
+ //name of the zip entry holding sheet data, e.g. /xl/worksheets/sheet1.xml
+ String sheetRef = sheet.getPackagePart().getPartName().getName();
+
+ //save the template
+ try (FileOutputStream os = new FileOutputStream("template.xlsx")) {
+ wb.write(os);
+ }
+
+ //Step 2. Generate XML file.
+ File tmp = File.createTempFile("sheet", ".xml");
+ try (
+ FileOutputStream stream = new FileOutputStream(tmp);
+ Writer fw = new OutputStreamWriter(stream, XML_ENCODING)
+ ) {
+ generate(fw, styles);
+ }
+
+ //Step 3. Substitute the template entry with the generated data
+ try (FileOutputStream out = new FileOutputStream("big-grid.xlsx")) {
+ substitute(new File("template.xlsx"), tmp, sheetRef.substring(1), out);
+ }
+ }
+ }
+
+ /**
+ * Create a library of cell styles.
+ */
+ private static Map<String, XSSFCellStyle> createStyles(XSSFWorkbook wb){
+ Map<String, XSSFCellStyle> styles = new HashMap<>();
+ XSSFDataFormat fmt = wb.createDataFormat();
+
+ XSSFCellStyle style1 = wb.createCellStyle();
+ style1.setAlignment(HorizontalAlignment.RIGHT);
+ style1.setDataFormat(fmt.getFormat("0.0%"));
+ styles.put("percent", style1);
+
+ XSSFCellStyle style2 = wb.createCellStyle();
+ style2.setAlignment(HorizontalAlignment.CENTER);
+ style2.setDataFormat(fmt.getFormat("0.0X"));
+ styles.put("coeff", style2);
+
+ XSSFCellStyle style3 = wb.createCellStyle();
+ style3.setAlignment(HorizontalAlignment.RIGHT);
+ style3.setDataFormat(fmt.getFormat("$#,##0.00"));
+ styles.put("currency", style3);
+
+ XSSFCellStyle style4 = wb.createCellStyle();
+ style4.setAlignment(HorizontalAlignment.RIGHT);
+ style4.setDataFormat(fmt.getFormat("mmm dd"));
+ styles.put("date", style4);
+
+ XSSFCellStyle style5 = wb.createCellStyle();
+ XSSFFont headerFont = wb.createFont();
+ headerFont.setBold(true);
+ style5.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
+ style5.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+ style5.setFont(headerFont);
+ styles.put("header", style5);
+
+ return styles;
+ }
+
+ private static void generate(Writer out, Map<String, XSSFCellStyle> styles) throws Exception {
+
+ Calendar calendar = LocaleUtil.getLocaleCalendar();
+
+ SpreadsheetWriter sw = new SpreadsheetWriter(out);
+ sw.beginSheet();
+
+ //insert header row
+ sw.insertRow(0);
+ int styleIndex = styles.get("header").getIndex();
+ sw.createCell(0, "Title", styleIndex);
+ sw.createCell(1, "% Change", styleIndex);
+ sw.createCell(2, "Ratio", styleIndex);
+ sw.createCell(3, "Expenses", styleIndex);
+ sw.createCell(4, "Date", styleIndex);
+
+ sw.endRow();
+
+ //write data rows
+ for (int rownum = 1; rownum < 100000; rownum++) {
+ sw.insertRow(rownum);
+
+ sw.createCell(0, "Hello, " + rownum + "!");
+ sw.createCell(1, (double)rnd.nextInt(100)/100, styles.get("percent").getIndex());
+ sw.createCell(2, (double)rnd.nextInt(10)/10, styles.get("coeff").getIndex());
+ sw.createCell(3, rnd.nextInt(10000), styles.get("currency").getIndex());
+ sw.createCell(4, calendar, styles.get("date").getIndex());
+
+ sw.endRow();
+
+ calendar.roll(Calendar.DAY_OF_YEAR, 1);
+ }
+ sw.endSheet();
+ }
+
+ /**
+ *
+ * @param zipfile the template file
+ * @param tmpfile the XML file with the sheet data
+ * @param entry the name of the sheet entry to substitute, e.g. xl/worksheets/sheet1.xml
+ * @param out the stream to write the result to
+ */
+ private static void substitute(File zipfile, File tmpfile, String entry, OutputStream out) throws IOException {
+ try (ZipFile zip = ZipHelper.openZipFile(zipfile)) {
+ try (ZipArchiveOutputStream zos = new ZipArchiveOutputStream(out)) {
+ Enumeration<? extends ZipArchiveEntry> en = zip.getEntries();
+ while (en.hasMoreElements()) {
+ ZipArchiveEntry ze = en.nextElement();
+ if (!ze.getName().equals(entry)) {
+ zos.putArchiveEntry(new ZipArchiveEntry(ze.getName()));
+ try (InputStream is = zip.getInputStream(ze)) {
+ copyStream(is, zos);
+ }
+ zos.closeArchiveEntry();
+ }
+ }
+ zos.putArchiveEntry(new ZipArchiveEntry(entry));
+ try (InputStream is = new FileInputStream(tmpfile)) {
+ copyStream(is, zos);
+ }
+ zos.closeArchiveEntry();
+ }
+ }
+ }
+
+ private static void copyStream(InputStream in, OutputStream out) throws IOException {
+ byte[] chunk = new byte[1024];
+ int count;
+ while ((count = in.read(chunk)) >=0 ) {
+ out.write(chunk,0,count);
+ }
+ }
+
+ /**
+ * Writes spreadsheet data in a Writer.
+ * (YK: in future it may evolve in a full-featured API for streaming data in Excel)
+ */
+ public static class SpreadsheetWriter {
+ private final Writer _out;
+ private int _rownum;
+
+ SpreadsheetWriter(Writer out){
+ _out = out;
+ }
+
+ void beginSheet() throws IOException {
+ _out.write("<?xml version=\"1.0\" encoding=\""+XML_ENCODING+"\"?>" +
+ "<worksheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">" );
+ _out.write("<sheetData>\n");
+ }
+
+ void endSheet() throws IOException {
+ _out.write("</sheetData>");
+ _out.write("</worksheet>");
+ }
+
+ /**
+ * Insert a new row
+ *
+ * @param rownum 0-based row number
+ */
+ void insertRow(int rownum) throws IOException {
+ _out.write("<row r=\""+(rownum+1)+"\">\n");
+ this._rownum = rownum;
+ }
+
+ /**
+ * Insert row end marker
+ */
+ void endRow() throws IOException {
+ _out.write("</row>\n");
+ }
+
+ public void createCell(int columnIndex, String value, int styleIndex) throws IOException {
+ String ref = new CellReference(_rownum, columnIndex).formatAsString();
+ _out.write("<c r=\""+ref+"\" t=\"inlineStr\"");
+ if(styleIndex != -1) {
+ _out.write(" s=\""+styleIndex+"\"");
+ }
+ _out.write(">");
+ _out.write("<is><t>"+value+"</t></is>");
+ _out.write("</c>");
+ }
+
+ public void createCell(int columnIndex, String value) throws IOException {
+ createCell(columnIndex, value, -1);
+ }
+
+ public void createCell(int columnIndex, double value, int styleIndex) throws IOException {
+ String ref = new CellReference(_rownum, columnIndex).formatAsString();
+ _out.write("<c r=\""+ref+"\" t=\"n\"");
+ if(styleIndex != -1) {
+ _out.write(" s=\""+styleIndex+"\"");
+ }
+ _out.write(">");
+ _out.write("<v>"+value+"</v>");
+ _out.write("</c>");
+ }
+
+ public void createCell(int columnIndex, double value) throws IOException {
+ createCell(columnIndex, value, -1);
+ }
+
+ public void createCell(int columnIndex, Calendar value, int styleIndex) throws IOException {
+ createCell(columnIndex, DateUtil.getExcelDate(value, false), styleIndex);
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/CalendarDemo.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/CalendarDemo.java
new file mode 100644
index 0000000000..fa06960bfc
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/CalendarDemo.java
@@ -0,0 +1,242 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.PrintOrientation;
+import org.apache.poi.ss.usermodel.VerticalAlignment;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.util.LocaleUtil;
+import org.apache.poi.xssf.usermodel.XSSFCell;
+import org.apache.poi.xssf.usermodel.XSSFCellStyle;
+import org.apache.poi.xssf.usermodel.XSSFColor;
+import org.apache.poi.xssf.usermodel.XSSFFont;
+import org.apache.poi.xssf.usermodel.XSSFPrintSetup;
+import org.apache.poi.xssf.usermodel.XSSFRow;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * A monthly calendar created using Apache POI. Each month is on a separate sheet.
+ * This is a version of org.apache.poi.ss.examples.CalendarDemo that demonstrates
+ * some XSSF features not avaiable when using common HSSF-XSSF interfaces.
+ *
+ * <pre>
+ * Usage:
+ * CalendarDemo &lt;year&gt;
+ * </pre>
+ *
+ * @author Yegor Kozlov
+ */
+public class CalendarDemo {
+
+ private static final String[] days = {
+ "Sunday", "Monday", "Tuesday",
+ "Wednesday", "Thursday", "Friday", "Saturday"};
+
+ private static final String[] months = {
+ "January", "February", "March","April", "May", "June","July", "August",
+ "September","October", "November", "December"};
+
+ public static void main(String[] args) throws Exception {
+
+ Calendar calendar = LocaleUtil.getLocaleCalendar();
+ if(args.length > 0) calendar.set(Calendar.YEAR, Integer.parseInt(args[0]));
+
+ int year = calendar.get(Calendar.YEAR);
+
+ try (XSSFWorkbook wb = new XSSFWorkbook()) {
+ Map<String, XSSFCellStyle> styles = createStyles(wb);
+
+ for (int month = 0; month < 12; month++) {
+ calendar.set(Calendar.MONTH, month);
+ calendar.set(Calendar.DAY_OF_MONTH, 1);
+ //create a sheet for each month
+ XSSFSheet sheet = wb.createSheet(months[month]);
+
+ //turn off gridlines
+ sheet.setDisplayGridlines(false);
+ sheet.setPrintGridlines(false);
+ XSSFPrintSetup printSetup = sheet.getPrintSetup();
+ printSetup.setOrientation(PrintOrientation.LANDSCAPE);
+ sheet.setFitToPage(true);
+ sheet.setHorizontallyCenter(true);
+
+ //the header row: centered text in 48pt font
+ XSSFRow headerRow = sheet.createRow(0);
+ headerRow.setHeightInPoints(80);
+ XSSFCell titleCell = headerRow.createCell(0);
+ titleCell.setCellValue(months[month] + " " + year);
+ titleCell.setCellStyle(styles.get("title"));
+ sheet.addMergedRegion(CellRangeAddress.valueOf("$A$1:$N$1"));
+
+ //header with month titles
+ XSSFRow monthRow = sheet.createRow(1);
+ for (int i = 0; i < days.length; i++) {
+ //for compatibility with HSSF we have to set column width in units of 1/256th of a character width
+ sheet.setColumnWidth(i * 2, 5 * 256); //the column is 5 characters wide
+ sheet.setColumnWidth(i * 2 + 1, 13 * 256); //the column is 13 characters wide
+ sheet.addMergedRegion(new CellRangeAddress(1, 1, i * 2, i * 2 + 1));
+ XSSFCell monthCell = monthRow.createCell(i * 2);
+ monthCell.setCellValue(days[i]);
+ monthCell.setCellStyle(styles.get("month"));
+ }
+
+ int cnt = 1, day = 1;
+ int rownum = 2;
+ for (int j = 0; j < 6; j++) {
+ XSSFRow row = sheet.createRow(rownum++);
+ row.setHeightInPoints(100);
+ for (int i = 0; i < days.length; i++) {
+ XSSFCell dayCell_1 = row.createCell(i * 2);
+ XSSFCell dayCell_2 = row.createCell(i * 2 + 1);
+
+ int day_of_week = calendar.get(Calendar.DAY_OF_WEEK);
+ if (cnt >= day_of_week && calendar.get(Calendar.MONTH) == month) {
+ dayCell_1.setCellValue(day);
+ calendar.set(Calendar.DAY_OF_MONTH, ++day);
+
+ if (i == 0 || i == days.length - 1) {
+ dayCell_1.setCellStyle(styles.get("weekend_left"));
+ dayCell_2.setCellStyle(styles.get("weekend_right"));
+ } else {
+ dayCell_1.setCellStyle(styles.get("workday_left"));
+ dayCell_2.setCellStyle(styles.get("workday_right"));
+ }
+ } else {
+ dayCell_1.setCellStyle(styles.get("grey_left"));
+ dayCell_2.setCellStyle(styles.get("grey_right"));
+ }
+ cnt++;
+ }
+ if (calendar.get(Calendar.MONTH) > month) break;
+ }
+ }
+
+ // Write the output to a file
+ try (FileOutputStream out = new FileOutputStream("calendar-" + year + ".xlsx")) {
+ wb.write(out);
+ }
+
+ }
+ }
+
+ /**
+ * cell styles used for formatting calendar sheets
+ */
+ private static Map<String, XSSFCellStyle> createStyles(XSSFWorkbook wb){
+ Map<String, XSSFCellStyle> styles = new HashMap<>();
+
+ XSSFCellStyle style;
+ XSSFFont titleFont = wb.createFont();
+ titleFont.setFontHeightInPoints((short)48);
+ titleFont.setColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
+ style = wb.createCellStyle();
+ style.setAlignment(HorizontalAlignment.CENTER);
+ style.setVerticalAlignment(VerticalAlignment.CENTER);
+ style.setFont(titleFont);
+ styles.put("title", style);
+
+ XSSFFont monthFont = wb.createFont();
+ monthFont.setFontHeightInPoints((short)12);
+ monthFont.setColor(new XSSFColor(new java.awt.Color(255, 255, 255), wb.getStylesSource().getIndexedColors()));
+ monthFont.setBold(true);
+ style = wb.createCellStyle();
+ style.setAlignment(HorizontalAlignment.CENTER);
+ style.setVerticalAlignment(VerticalAlignment.CENTER);
+ style.setFillForegroundColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+ style.setFont(monthFont);
+ styles.put("month", style);
+
+ XSSFFont dayFont = wb.createFont();
+ dayFont.setFontHeightInPoints((short)14);
+ dayFont.setBold(true);
+ style = wb.createCellStyle();
+ style.setAlignment(HorizontalAlignment.LEFT);
+ style.setVerticalAlignment(VerticalAlignment.TOP);
+ style.setFillForegroundColor(new XSSFColor(new java.awt.Color(228, 232, 243), wb.getStylesSource().getIndexedColors()));
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+ style.setBorderLeft(BorderStyle.THIN);
+ style.setLeftBorderColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
+ style.setBorderBottom(BorderStyle.THIN);
+ style.setBottomBorderColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
+ style.setFont(dayFont);
+ styles.put("weekend_left", style);
+
+ style = wb.createCellStyle();
+ style.setAlignment(HorizontalAlignment.CENTER);
+ style.setVerticalAlignment(VerticalAlignment.TOP);
+ style.setFillForegroundColor(new XSSFColor(new java.awt.Color(228, 232, 243), wb.getStylesSource().getIndexedColors()));
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+ style.setBorderRight(BorderStyle.THIN);
+ style.setRightBorderColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
+ style.setBorderBottom(BorderStyle.THIN);
+ style.setBottomBorderColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
+ styles.put("weekend_right", style);
+
+ style = wb.createCellStyle();
+ style.setAlignment(HorizontalAlignment.LEFT);
+ style.setVerticalAlignment(VerticalAlignment.TOP);
+ style.setBorderLeft(BorderStyle.THIN);
+ style.setFillForegroundColor(new XSSFColor(new java.awt.Color(255, 255, 255), wb.getStylesSource().getIndexedColors()));
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+ style.setLeftBorderColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
+ style.setBorderBottom(BorderStyle.THIN);
+ style.setBottomBorderColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
+ style.setFont(dayFont);
+ styles.put("workday_left", style);
+
+ style = wb.createCellStyle();
+ style.setAlignment(HorizontalAlignment.CENTER);
+ style.setVerticalAlignment(VerticalAlignment.TOP);
+ style.setFillForegroundColor(new XSSFColor(new java.awt.Color(255, 255, 255), wb.getStylesSource().getIndexedColors()));
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+ style.setBorderRight(BorderStyle.THIN);
+ style.setRightBorderColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
+ style.setBorderBottom(BorderStyle.THIN);
+ style.setBottomBorderColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
+ styles.put("workday_right", style);
+
+ style = wb.createCellStyle();
+ style.setBorderLeft(BorderStyle.THIN);
+ style.setFillForegroundColor(new XSSFColor(new java.awt.Color(234, 234, 234), wb.getStylesSource().getIndexedColors()));
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+ style.setBorderBottom(BorderStyle.THIN);
+ style.setBottomBorderColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
+ styles.put("grey_left", style);
+
+ style = wb.createCellStyle();
+ style.setFillForegroundColor(new XSSFColor(new java.awt.Color(234, 234, 234), wb.getStylesSource().getIndexedColors()));
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+ style.setBorderRight(BorderStyle.THIN);
+ style.setRightBorderColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
+ style.setBorderBottom(BorderStyle.THIN);
+ style.setBottomBorderColor(new XSSFColor(new java.awt.Color(39, 51, 89), wb.getStylesSource().getIndexedColors()));
+ styles.put("grey_right", style);
+
+ return styles;
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/CellComments.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/CellComments.java
new file mode 100644
index 0000000000..eb5757779c
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/CellComments.java
@@ -0,0 +1,88 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.ClientAnchor;
+import org.apache.poi.ss.usermodel.Comment;
+import org.apache.poi.ss.usermodel.CreationHelper;
+import org.apache.poi.ss.usermodel.Drawing;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.usermodel.RichTextString;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.util.CellAddress;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Demonstrates how to work with excel cell comments.
+ *
+ * <p>
+ * Excel comment is a kind of a text shape,
+ * so inserting a comment is very similar to placing a text box in a worksheet
+ * </p>
+ *
+ * @author Yegor Kozlov
+ */
+public class CellComments {
+ public static void main(String[] args) throws IOException {
+ try (Workbook wb = new XSSFWorkbook()) {
+
+ CreationHelper factory = wb.getCreationHelper();
+
+ Sheet sheet = wb.createSheet();
+
+ Cell cell1 = sheet.createRow(3).createCell(5);
+ cell1.setCellValue("F4");
+
+ Drawing<?> drawing = sheet.createDrawingPatriarch();
+
+ ClientAnchor anchor = factory.createClientAnchor();
+
+ Comment comment1 = drawing.createCellComment(anchor);
+ RichTextString str1 = factory.createRichTextString("Hello, World!");
+ comment1.setString(str1);
+ comment1.setAuthor("Apache POI");
+ cell1.setCellComment(comment1);
+
+ Cell cell2 = sheet.createRow(2).createCell(2);
+ cell2.setCellValue("C3");
+
+ Comment comment2 = drawing.createCellComment(anchor);
+ RichTextString str2 = factory.createRichTextString("XSSF can set cell comments");
+ //apply custom font to the text in the comment
+ Font font = wb.createFont();
+ font.setFontName("Arial");
+ font.setFontHeightInPoints((short) 14);
+ font.setBold(true);
+ font.setColor(IndexedColors.RED.getIndex());
+ str2.applyFont(font);
+
+ comment2.setString(str2);
+ comment2.setAuthor("Apache POI");
+ comment2.setAddress(new CellAddress("C3"));
+
+ try (FileOutputStream out = new FileOutputStream("comments.xlsx")) {
+ wb.write(out);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/CreateCell.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/CreateCell.java
new file mode 100644
index 0000000000..36e93dec2f
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/CreateCell.java
@@ -0,0 +1,88 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Date;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.CreationHelper;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.RichTextString;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Illustrates how to create cell and set values of different types.
+ */
+public class CreateCell {
+
+ public static void main(String[] args) throws IOException {
+ try (Workbook wb = new XSSFWorkbook()) { //or new HSSFWorkbook();
+ CreationHelper creationHelper = wb.getCreationHelper();
+ Sheet sheet = wb.createSheet("new sheet");
+
+ // Create a row and put some cells in it. Rows are 0 based.
+ Row row = sheet.createRow((short) 0);
+ // Create a cell and put a value in it.
+ Cell cell = row.createCell((short) 0);
+ cell.setCellValue(1);
+
+ //numeric value
+ row.createCell(1).setCellValue(1.2);
+
+ //plain string value
+ row.createCell(2).setCellValue("This is a string cell");
+
+ //rich text string
+ RichTextString str = creationHelper.createRichTextString("Apache");
+ Font font = wb.createFont();
+ font.setItalic(true);
+ font.setUnderline(Font.U_SINGLE);
+ str.applyFont(font);
+ row.createCell(3).setCellValue(str);
+
+ //boolean value
+ row.createCell(4).setCellValue(true);
+
+ //formula
+ row.createCell(5).setCellFormula("SUM(A1:B1)");
+
+ //date
+ CellStyle style = wb.createCellStyle();
+ style.setDataFormat(creationHelper.createDataFormat().getFormat("m/d/yy h:mm"));
+ cell = row.createCell(6);
+ cell.setCellValue(new Date());
+ cell.setCellStyle(style);
+
+ //hyperlink
+ row.createCell(7).setCellFormula("SUM(A1:B1)");
+ cell.setCellFormula("HYPERLINK(\"http://google.com\",\"Google\")");
+
+
+ // Write the output to a file
+ try (FileOutputStream fileOut = new FileOutputStream("ooxml-cell.xlsx")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/CreatePivotTable.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/CreatePivotTable.java
new file mode 100644
index 0000000000..991dd2f71a
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/CreatePivotTable.java
@@ -0,0 +1,106 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ ==================================================================== */
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.ss.SpreadsheetVersion;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.DataConsolidateFunction;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.util.AreaReference;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.xssf.usermodel.XSSFPivotTable;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+public class CreatePivotTable {
+
+ public static void main(String[] args) throws FileNotFoundException, IOException, InvalidFormatException {
+ try (XSSFWorkbook wb = new XSSFWorkbook()) {
+ XSSFSheet sheet = wb.createSheet();
+
+ //Create some data to build the pivot table on
+ setCellData(sheet);
+
+ AreaReference source = new AreaReference("A1:D4", SpreadsheetVersion.EXCEL2007);
+ CellReference position = new CellReference("H5");
+ // Create a pivot table on this sheet, with H5 as the top-left cell..
+ // The pivot table's data source is on the same sheet in A1:D4
+ XSSFPivotTable pivotTable = sheet.createPivotTable(source, position);
+ //Configure the pivot table
+ //Use first column as row label
+ pivotTable.addRowLabel(0);
+ //Sum up the second column
+ pivotTable.addColumnLabel(DataConsolidateFunction.SUM, 1);
+ //Set the third column as filter
+ pivotTable.addColumnLabel(DataConsolidateFunction.AVERAGE, 2);
+ //Add filter on forth column
+ pivotTable.addReportFilter(3);
+
+ try (FileOutputStream fileOut = new FileOutputStream("ooxml-pivottable.xlsx")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+
+ public static void setCellData(XSSFSheet sheet){
+ Row row1 = sheet.createRow(0);
+ // Create a cell and put a value in it.
+ Cell cell11 = row1.createCell(0);
+ cell11.setCellValue("Names");
+ Cell cell12 = row1.createCell(1);
+ cell12.setCellValue("#");
+ Cell cell13 = row1.createCell(2);
+ cell13.setCellValue("%");
+ Cell cell14 = row1.createCell(3);
+ cell14.setCellValue("Human");
+
+ Row row2 = sheet.createRow(1);
+ Cell cell21 = row2.createCell(0);
+ cell21.setCellValue("Jane");
+ Cell cell22 = row2.createCell(1);
+ cell22.setCellValue(10);
+ Cell cell23 = row2.createCell(2);
+ cell23.setCellValue(100);
+ Cell cell24 = row2.createCell(3);
+ cell24.setCellValue("Yes");
+
+ Row row3 = sheet.createRow(2);
+ Cell cell31 = row3.createCell(0);
+ cell31.setCellValue("Tarzan");
+ Cell cell32 = row3.createCell(1);
+ cell32.setCellValue(5);
+ Cell cell33 = row3.createCell(2);
+ cell33.setCellValue(90);
+ Cell cell34 = row3.createCell(3);
+ cell34.setCellValue("Yes");
+
+ Row row4 = sheet.createRow(3);
+ Cell cell41 = row4.createCell(0);
+ cell41.setCellValue("Terk");
+ Cell cell42 = row4.createCell(1);
+ cell42.setCellValue(10);
+ Cell cell43 = row4.createCell(2);
+ cell43.setCellValue(90);
+ Cell cell44 = row4.createCell(3);
+ cell44.setCellValue("No");
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/CreatePivotTable2.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/CreatePivotTable2.java
new file mode 100644
index 0000000000..53951d0ebd
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/CreatePivotTable2.java
@@ -0,0 +1,125 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ ==================================================================== */
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Calendar;
+import java.util.Date;
+
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.ss.SpreadsheetVersion;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.DataConsolidateFunction;
+import org.apache.poi.ss.usermodel.DataFormat;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.util.AreaReference;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.util.LocaleUtil;
+import org.apache.poi.xssf.usermodel.XSSFPivotTable;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+public class CreatePivotTable2 {
+
+ public static void main(String[] args) throws FileNotFoundException, IOException, InvalidFormatException {
+ try (XSSFWorkbook wb = new XSSFWorkbook()) {
+ XSSFSheet sheet = wb.createSheet();
+
+ //Create some data to build the pivot table on
+ setCellData(sheet);
+
+ AreaReference source = new AreaReference("A1:E7", SpreadsheetVersion.EXCEL2007);
+ CellReference position = new CellReference("H1");
+ // Create a pivot table on this sheet, with H1 as the top-left cell..
+ // The pivot table's data source is on the same sheet in A1:E7
+ XSSFPivotTable pivotTable = sheet.createPivotTable(source, position);
+ //Configure the pivot table
+ //Use first column as row label
+ pivotTable.addRowLabel(0);
+ //Sum up the second column with column title and data format
+ pivotTable.addColumnLabel(DataConsolidateFunction.SUM, 1, "Values", "#,##0.00");
+ //Use third column (month) as columns (side by side)
+ pivotTable.addColLabel(3, "DD.MM.YYYY");
+
+ //Add filter on forth column
+ pivotTable.addReportFilter(4);
+
+ try (FileOutputStream fileOut = new FileOutputStream("ooxml-pivottable2.xlsx")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+
+ public static void setCellData(XSSFSheet sheet){
+ Calendar cal1 = LocaleUtil.getLocaleCalendar();
+ cal1.set(2017, 0, 1, 0, 0, 0);
+ Calendar cal2 = LocaleUtil.getLocaleCalendar();
+ cal2.set(2017, 1, 1, 0, 0, 0);
+ Row row1 = sheet.createRow(0);
+ // Create a cell and put a value in it.
+ // first row are column titles
+ Cell cell11 = row1.createCell(0);
+ cell11.setCellValue("Names");
+ Cell cell12 = row1.createCell(1);
+ cell12.setCellValue("Values");
+ Cell cell13 = row1.createCell(2);
+ cell13.setCellValue("%");
+ Cell cell14 = row1.createCell(3);
+ cell14.setCellValue("Month");
+ Cell cell15 = row1.createCell(4);
+ cell15.setCellValue("No");
+
+ CellStyle csDbl = sheet.getWorkbook().createCellStyle();
+ DataFormat dfDbl = sheet.getWorkbook().createDataFormat();
+ csDbl.setDataFormat(dfDbl.getFormat("#,##0.00"));
+
+ CellStyle csDt = sheet.getWorkbook().createCellStyle();
+ DataFormat dfDt = sheet.getWorkbook().createDataFormat();
+ csDt.setDataFormat(dfDt.getFormat("dd/MM/yyyy"));
+ // data
+ setDataRow(sheet, 1, "Jane", 1120.5, 100, cal1.getTime(), 1, csDbl, csDt);
+ setDataRow(sheet, 2, "Jane", 1453.2, 95, cal2.getTime(), 2, csDbl, csDt);
+
+ setDataRow(sheet, 3, "Tarzan", 1869.8, 88, cal1.getTime(), 1, csDbl, csDt);
+ setDataRow(sheet, 4, "Tarzan", 1536.2, 92, cal2.getTime(), 2, csDbl, csDt);
+
+ setDataRow(sheet, 5, "Terk", 1624.1, 75, cal1.getTime(), 1, csDbl, csDt);
+ setDataRow(sheet, 6, "Terk", 1569.3, 82, cal2.getTime(), 2, csDbl, csDt);
+ sheet.autoSizeColumn(3);
+ }
+
+ public static void setDataRow(XSSFSheet sheet, int rowNum, String name, double v1, int v2, Date dt, int no, CellStyle csDbl, CellStyle csDt){
+ Row row = sheet.createRow(rowNum);
+ // set the values for one row
+ Cell c1 = row.createCell(0);
+ c1.setCellValue(name);
+ Cell c2 = row.createCell(1);
+ c2.setCellValue(v1);
+ c2.setCellStyle(csDbl);
+ Cell c3 = row.createCell(2);
+ c3.setCellValue(v2);
+ Cell c4 = row.createCell(3);
+ c4.setCellValue(dt);
+ c4.setCellStyle(csDt);
+ Cell c5 = row.createCell(4);
+ c5.setCellValue(no);
+ }
+
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/CreateTable.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/CreateTable.java
new file mode 100644
index 0000000000..7e1d56ad00
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/CreateTable.java
@@ -0,0 +1,87 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.ss.util.AreaReference;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.xssf.usermodel.XSSFCell;
+import org.apache.poi.xssf.usermodel.XSSFRow;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFTable;
+import org.apache.poi.xssf.usermodel.XSSFTableStyleInfo;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Demonstrates how to create a simple table using Apache POI.
+ */
+public class CreateTable {
+
+ public static void main(String[] args) throws IOException {
+
+ try (XSSFWorkbook wb = new XSSFWorkbook()) {
+ XSSFSheet sheet = wb.createSheet();
+
+ // Set which area the table should be placed in
+ AreaReference reference = wb.getCreationHelper().createAreaReference(
+ new CellReference(0, 0), new CellReference(2, 2));
+
+ // Create
+ XSSFTable table = sheet.createTable(reference);
+ table.setName("Test");
+ table.setDisplayName("Test_Table");
+
+ // For now, create the initial style in a low-level way
+ table.getCTTable().addNewTableStyleInfo();
+ table.getCTTable().getTableStyleInfo().setName("TableStyleMedium2");
+
+ // Style the table
+ XSSFTableStyleInfo style = (XSSFTableStyleInfo) table.getStyle();
+ style.setName("TableStyleMedium2");
+ style.setShowColumnStripes(false);
+ style.setShowRowStripes(true);
+ style.setFirstColumn(false);
+ style.setLastColumn(false);
+ style.setShowRowStripes(true);
+ style.setShowColumnStripes(true);
+
+ // Set the values for the table
+ XSSFRow row;
+ XSSFCell cell;
+ for (int i = 0; i < 3; i++) {
+ // Create row
+ row = sheet.createRow(i);
+ for (int j = 0; j < 3; j++) {
+ // Create cell
+ cell = row.createCell(j);
+ if (i == 0) {
+ cell.setCellValue("Column" + (j + 1));
+ } else {
+ cell.setCellValue((i + 1.0) * (j + 1.0));
+ }
+ }
+ }
+
+ // Save
+ try (FileOutputStream fileOut = new FileOutputStream("ooxml-table.xlsx")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/CreateUserDefinedDataFormats.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/CreateUserDefinedDataFormats.java
new file mode 100644
index 0000000000..03d88d67ef
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/CreateUserDefinedDataFormats.java
@@ -0,0 +1,67 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.DataFormat;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * How to set user-defined date formats
+ */
+public class CreateUserDefinedDataFormats {
+
+
+ public static void main(String[]args) throws IOException {
+ try (Workbook wb = new XSSFWorkbook()) { //or new HSSFWorkbook();
+ Sheet sheet = wb.createSheet("format sheet");
+ CellStyle style;
+ DataFormat format = wb.createDataFormat();
+ Row row;
+ Cell cell;
+ short rowNum = 0;
+ short colNum = 0;
+
+ row = sheet.createRow(rowNum);
+ cell = row.createCell(colNum);
+ cell.setCellValue(11111.25);
+ style = wb.createCellStyle();
+ style.setDataFormat(format.getFormat("0.0"));
+ cell.setCellStyle(style);
+
+ row = sheet.createRow(++rowNum);
+ cell = row.createCell(colNum);
+ cell.setCellValue(11111.25);
+ style = wb.createCellStyle();
+ style.setDataFormat(format.getFormat("#,##0.0000"));
+ cell.setCellStyle(style);
+
+ try (FileOutputStream fileOut = new FileOutputStream("ooxml_dataFormat.xlsx")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/CustomXMLMapping.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/CustomXMLMapping.java
new file mode 100644
index 0000000000..ebc04a4d33
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/CustomXMLMapping.java
@@ -0,0 +1,47 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.ByteArrayOutputStream;
+
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.xssf.extractor.XSSFExportToXml;
+import org.apache.poi.xssf.usermodel.XSSFMap;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Print all custom XML mappings registered in the given workbook
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class CustomXMLMapping {
+
+ private CustomXMLMapping() {}
+
+ public static void main(String[] args) throws Exception {
+ try (OPCPackage pkg = OPCPackage.open(args[0]);
+ XSSFWorkbook wb = new XSSFWorkbook(pkg)) {
+ for (XSSFMap map : wb.getCustomXMLMappings()) {
+ XSSFExportToXml exporter = new XSSFExportToXml(map);
+
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ exporter.exportToXML(os, true);
+ String xml = os.toString("UTF-8");
+ System.out.println(xml);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/EmbeddedObjects.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/EmbeddedObjects.java
new file mode 100644
index 0000000000..b4af95c5ae
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/EmbeddedObjects.java
@@ -0,0 +1,67 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.Closeable;
+import java.io.InputStream;
+
+import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hwpf.HWPFDocument;
+import org.apache.poi.openxml4j.opc.PackagePart;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+
+/**
+ * Demonstrates how you can extract embedded data from a .xlsx file
+ */
+public class EmbeddedObjects {
+ public static void main(String[] args) throws Exception {
+ try (XSSFWorkbook workbook = new XSSFWorkbook(args[0])) {
+ for (PackagePart pPart : workbook.getAllEmbeddedParts()) {
+ String contentType = pPart.getContentType();
+ try (InputStream is = pPart.getInputStream()) {
+ Closeable document;
+ if (contentType.equals("application/vnd.ms-excel")) {
+ // Excel Workbook - either binary or OpenXML
+ document = new HSSFWorkbook(is);
+ } else if (contentType.equals("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")) {
+ // Excel Workbook - OpenXML file format
+ document = new XSSFWorkbook(is);
+ } else if (contentType.equals("application/msword")) {
+ // Word Document - binary (OLE2CDF) file format
+ document = new HWPFDocument(is);
+ } else if (contentType.equals("application/vnd.openxmlformats-officedocument.wordprocessingml.document")) {
+ // Word Document - OpenXML file format
+ document = new XWPFDocument(is);
+ } else if (contentType.equals("application/vnd.ms-powerpoint")) {
+ // PowerPoint Document - binary file format
+ document = new HSLFSlideShow(is);
+ } else if (contentType.equals("application/vnd.openxmlformats-officedocument.presentationml.presentation")) {
+ // PowerPoint Document - OpenXML file format
+ document = new XMLSlideShow(is);
+ } else {
+ // Any other type of embedded object.
+ document = is;
+ }
+ document.close();
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/ExcelChartWithTargetLine.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/ExcelChartWithTargetLine.java
new file mode 100644
index 0000000000..a80916148a
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/ExcelChartWithTargetLine.java
@@ -0,0 +1,234 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.xddf.usermodel.PresetColor;
+import org.apache.poi.xddf.usermodel.XDDFColor;
+import org.apache.poi.xddf.usermodel.XDDFFillProperties;
+import org.apache.poi.xddf.usermodel.XDDFLineProperties;
+import org.apache.poi.xddf.usermodel.XDDFShapeProperties;
+import org.apache.poi.xddf.usermodel.XDDFSolidFillProperties;
+import org.apache.poi.xddf.usermodel.chart.AxisPosition;
+import org.apache.poi.xddf.usermodel.chart.AxisTickLabelPosition;
+import org.apache.poi.xddf.usermodel.chart.BarDirection;
+import org.apache.poi.xddf.usermodel.chart.ChartTypes;
+import org.apache.poi.xddf.usermodel.chart.LegendPosition;
+import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFCategoryAxis;
+import org.apache.poi.xddf.usermodel.chart.XDDFCategoryDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
+import org.apache.poi.xddf.usermodel.chart.XDDFLegendEntry;
+import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFScatterChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
+import org.apache.poi.xddf.usermodel.text.XDDFRunProperties;
+import org.apache.poi.xssf.usermodel.XSSFCell;
+import org.apache.poi.xssf.usermodel.XSSFChart;
+import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
+import org.apache.poi.xssf.usermodel.XSSFDrawing;
+import org.apache.poi.xssf.usermodel.XSSFRow;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * This example is based on original contributions by Axel Richter on StackOverflow.
+ *
+ * <em>Note from original author</em>:
+ * This only works for Excel since OpenOffice or LibreOffice Calc is not able having series having literal numeric values set.
+ *
+ * @see <a href="https://stackoverflow.com/questions/50772989/">Create target marker in a bar chart with openxmlformats</a>
+ * @see <a href="https://stackoverflow.com/questions/50873700/">Change axis color and font of the chart in openxmlformats</a>
+ * @see <a href="https://stackoverflow.com/questions/51530552/">Change colors of line chart Apache POI</a>
+ */
+public final class ExcelChartWithTargetLine {
+ private ExcelChartWithTargetLine() {}
+
+ private static final int NUM_OF_ROWS = 6;
+
+ private static void createChart(XSSFChart chart, XSSFSheet sheet, int[] chartedCols, double target) {
+ // some colors
+ XDDFFillProperties[] fills = new XDDFFillProperties[] {
+ new XDDFSolidFillProperties(XDDFColor.from(PresetColor.TURQUOISE)),
+ new XDDFSolidFillProperties(XDDFColor.from(PresetColor.CHARTREUSE)),
+ new XDDFSolidFillProperties(XDDFColor.from(PresetColor.LAVENDER)),
+ new XDDFSolidFillProperties(XDDFColor.from(PresetColor.CHOCOLATE)),
+ new XDDFSolidFillProperties(XDDFColor.from(PresetColor.TOMATO)),
+ new XDDFSolidFillProperties(XDDFColor.from(PresetColor.PLUM))
+ };
+ XDDFLineProperties solidTurquoise = new XDDFLineProperties(fills[0]);
+ XDDFLineProperties solidTomato = new XDDFLineProperties(fills[4]);
+ XDDFLineProperties solidPlum = new XDDFLineProperties(fills[5]);
+ XDDFSolidFillProperties solidAlmond = new XDDFSolidFillProperties(XDDFColor.from(PresetColor.BLANCHED_ALMOND));
+ XDDFSolidFillProperties solidGray = new XDDFSolidFillProperties(XDDFColor.from(PresetColor.DARK_SLATE_GRAY));
+
+
+ // the bar chart
+
+ XDDFCategoryAxis barCategories = chart.createCategoryAxis(AxisPosition.BOTTOM);
+ XDDFValueAxis leftValues = chart.createValueAxis(AxisPosition.LEFT);
+ leftValues.crossAxis(barCategories);
+ barCategories.crossAxis(leftValues);
+
+ // from https://stackoverflow.com/questions/50873700/
+ // colored major grid lines
+ leftValues.getOrAddMajorGridProperties().setLineProperties(solidTomato);
+ //colored axis line
+ leftValues.getOrAddShapeProperties().setLineProperties(solidPlum);
+ // axis font
+ XDDFRunProperties props = leftValues.getOrAddTextProperties();
+ props.setFontSize(14.0);
+ props.setFillProperties(fills[5]);
+
+ XDDFBarChartData bar = (XDDFBarChartData) chart.createData(ChartTypes.BAR, barCategories, leftValues);
+ bar.setVaryColors(true);
+ bar.setBarDirection(chartedCols.length > 1 ? BarDirection.COL : BarDirection.BAR);
+
+ for (int c : chartedCols) {
+ // the data sources
+ XDDFCategoryDataSource xs = XDDFDataSourcesFactory.fromStringCellRange(sheet,
+ new CellRangeAddress(1, NUM_OF_ROWS, 0, 0));
+ XDDFNumericalDataSource<Double> ys = XDDFDataSourcesFactory.fromNumericCellRange(sheet,
+ new CellRangeAddress(1, NUM_OF_ROWS, c, c));
+ XDDFBarChartData.Series series = (XDDFBarChartData.Series) bar.addSeries(xs, ys);
+ series.setTitle(null, new CellReference(sheet.getSheetName(), 0, c, true, true));
+ series.setFillProperties(fills[c]);
+ series.setLineProperties(solidTurquoise); // bar border color different from fill
+ }
+ chart.plot(bar);
+
+
+ // target line
+ // line of a scatter chart from 0 (min) to 1 (max) having value of target
+
+ XDDFValueAxis scatterX = chart.createValueAxis(AxisPosition.TOP);
+ scatterX.setVisible(false);
+ scatterX.setTickLabelPosition(AxisTickLabelPosition.NONE);
+ XDDFValueAxis scatterY = chart.createValueAxis(AxisPosition.RIGHT);
+ scatterY.setVisible(false);
+ scatterY.setTickLabelPosition(AxisTickLabelPosition.NONE);
+ scatterX.crossAxis(scatterY);
+ scatterY.crossAxis(scatterX);
+ if (chartedCols.length > 1) {
+ scatterX.setMaximum(1.0);
+ } else {
+ scatterY.setMaximum(1.0);
+ }
+
+ XDDFScatterChartData scatter = (XDDFScatterChartData) chart.createData(ChartTypes.SCATTER, scatterX, scatterY);
+ scatter.setVaryColors(false);
+
+ // This only works for Excel since OpenOffice or LibreOffice Calc does not support literal numeric data series.
+ XDDFNumericalDataSource<Double> targetDS = XDDFDataSourcesFactory.fromArray(new Double[] { target, target });
+ XDDFNumericalDataSource<Double> zeroOneDS = XDDFDataSourcesFactory.fromArray(new Double[] { 0.0, 1.0 });
+
+ if (chartedCols.length > 1) {
+ // BarDirection.COL then X axis is from 0 to 1 and Y axis is target axis
+ scatter.addSeries(zeroOneDS, targetDS).setLineProperties(solidTurquoise);
+ } else {
+ // BarDirection.BAR then X axis is target axis and Y axis is from 0 to 1
+ scatter.addSeries(targetDS, zeroOneDS).setLineProperties(solidTurquoise);
+ }
+
+ chart.plot(scatter);
+
+
+ // legend
+ if (chartedCols.length > 1) {
+ XDDFChartLegend legend = chart.getOrAddLegend();
+ legend.setPosition(LegendPosition.LEFT);
+ legend.setOverlay(false);
+
+ // delete additional target line series legend entry
+ XDDFLegendEntry entry = legend.addEntry();
+ entry.setIndex(0);
+ entry.setDelete(true);
+ }
+
+
+ // from https://stackoverflow.com/questions/51530552/
+ // customize the chart
+
+ // do not auto delete the title
+ chart.setAutoTitleDeleted(false);
+
+ // plot area background and border line
+ XDDFShapeProperties chartProps = chart.getOrAddShapeProperties();
+ chartProps.setFillProperties(solidAlmond);
+ chartProps.setLineProperties(new XDDFLineProperties(solidGray));
+
+ // line style of cat axis
+ XDDFLineProperties categoriesProps = new XDDFLineProperties(solidGray);
+ categoriesProps.setWidth(2.1);
+ barCategories.getOrAddShapeProperties().setLineProperties(categoriesProps);
+ }
+
+ private static XSSFClientAnchor createAnchor(XSSFDrawing drawing, int[] chartedCols) {
+ if (chartedCols.length > 1) {
+ return drawing.createAnchor(0, 0, 0, 0, 0, 8, 10, 23);
+ } else {
+ return drawing.createAnchor(0, 0, 0, 0, 0, 8, 5, 23);
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ try (XSSFWorkbook workbook = new XSSFWorkbook()) {
+ XSSFSheet sheet = workbook.createSheet("targetline");
+ final int NUM_OF_COLUMNS = 4;
+
+ // create some data
+ XSSFRow row;
+ XSSFCell cell;
+ String[] headings = new String[] { "Year", "Male", "Female", "Other" };
+ int rowIndex = 0;
+ row = sheet.createRow(rowIndex);
+ for (int colIndex = 0; colIndex < NUM_OF_COLUMNS; colIndex++) {
+ cell = row.createCell(colIndex);
+ cell.setCellValue(headings[colIndex]);
+ }
+ double[][] values = new double[][] { new double[] { 1980, 56.0, 44.1, 12.2 },
+ new double[] { 1985, 34.5, 41.0, 4 }, new double[] { 1990, 65.0, 68.5, 9.1 },
+ new double[] { 1995, 34.7, 47.6, 4.9 }, new double[] { 2000, 23.0, 64.5, 11.1 },
+ new double[] { 2005, 56.3, 69.8, 9.5 } };
+ for (; rowIndex < NUM_OF_ROWS; rowIndex++) {
+ row = sheet.createRow(rowIndex + 1);
+ for (int colIndex = 0; colIndex < NUM_OF_COLUMNS; colIndex++) {
+ cell = row.createCell(colIndex);
+ cell.setCellValue(values[rowIndex][colIndex]);
+ }
+ }
+
+ int[] chartedCols = new int[] { 1, 2 , 3 };
+
+ XSSFDrawing drawing = sheet.createDrawingPatriarch();
+ XSSFClientAnchor anchor = createAnchor(drawing, chartedCols);
+ XSSFChart chart = drawing.createChart(anchor);
+ createChart(chart, sheet, chartedCols, 42.0);
+
+ try (FileOutputStream fos = new FileOutputStream("ExcelChartWithTargetLine.xlsx")) {
+ workbook.write(fos);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/FillsAndColors.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/FillsAndColors.java
new file mode 100644
index 0000000000..baf462ce32
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/FillsAndColors.java
@@ -0,0 +1,65 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFRichTextString;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Fills and Colors
+ */
+public class FillsAndColors {
+ public static void main(String[] args) throws IOException {
+ try (Workbook wb = new XSSFWorkbook()) { //or new HSSFWorkbook();
+ Sheet sheet = wb.createSheet("new sheet");
+
+ // Create a row and put some cells in it. Rows are 0 based.
+ Row row = sheet.createRow(1);
+
+ // Aqua background
+ CellStyle style = wb.createCellStyle();
+ style.setFillBackgroundColor(IndexedColors.AQUA.getIndex());
+ style.setFillPattern(FillPatternType.BIG_SPOTS);
+ Cell cell = row.createCell(1);
+ cell.setCellValue(new XSSFRichTextString("X"));
+ cell.setCellStyle(style);
+
+ // Orange "foreground", foreground being the fill foreground not the font color.
+ style = wb.createCellStyle();
+ style.setFillForegroundColor(IndexedColors.ORANGE.getIndex());
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+ cell = row.createCell(2);
+ cell.setCellValue(new XSSFRichTextString("X"));
+ cell.setCellStyle(style);
+
+ // Write the output to a file
+ try (FileOutputStream fileOut = new FileOutputStream("fill_colors.xlsx")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/FitSheetToOnePage.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/FitSheetToOnePage.java
new file mode 100644
index 0000000000..389e87fd0b
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/FitSheetToOnePage.java
@@ -0,0 +1,46 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.PrintSetup;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+public class FitSheetToOnePage {
+
+ public static void main(String[]args) throws IOException {
+ try (Workbook wb = new XSSFWorkbook()) { //or new HSSFWorkbook();
+ Sheet sheet = wb.createSheet("format sheet");
+ PrintSetup ps = sheet.getPrintSetup();
+
+ sheet.setAutobreaks(true);
+
+ ps.setFitHeight((short) 1);
+ ps.setFitWidth((short) 1);
+
+ // Create various cells and rows for spreadsheet.
+
+ try (FileOutputStream fileOut = new FileOutputStream("fitSheetToOnePage.xlsx")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/HeadersAndFooters.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/HeadersAndFooters.java
new file mode 100644
index 0000000000..946ae50fd4
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/HeadersAndFooters.java
@@ -0,0 +1,84 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.Footer;
+import org.apache.poi.ss.usermodel.Header;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+public class HeadersAndFooters {
+
+ public static void main(String[]args) throws IOException {
+ try (Workbook wb = new XSSFWorkbook()) { //or new HSSFWorkbook();
+ Sheet sheet = wb.createSheet("first-header - format sheet");
+ sheet.createRow(0).createCell(0).setCellValue(123);
+
+ //set page numbers in the footer
+ Footer footer = sheet.getFooter();
+ //&P == current page number
+ //&N == page numbers
+ footer.setRight("Page &P of &N");
+
+
+ Header firstHeader = ((XSSFSheet) sheet).getFirstHeader();
+ //&F == workbook file name
+ firstHeader.setLeft("&F ......... first header");
+
+ for (int i = 0; i < 100; i = i + 10) {
+ sheet.createRow(i).createCell(0).setCellValue(123);
+ }
+
+
+ XSSFSheet sheet2 = (XSSFSheet) wb.createSheet("odd header-even footer");
+ Header oddHeader = sheet2.getOddHeader();
+ //&B == bold
+ //&E == double underline
+ //&D == date
+ oddHeader.setCenter("&B &E oddHeader &D ");
+
+ Footer evenFooter = sheet2.getEvenFooter();
+ evenFooter.setRight("even footer &P");
+ sheet2.createRow(10).createCell(0).setCellValue("Second sheet with an oddHeader and an evenFooter");
+
+ for (int i = 0; i < 200; i = i + 10) {
+ sheet2.createRow(i).createCell(0).setCellValue(123);
+ }
+
+ XSSFSheet sheet3 = (XSSFSheet) wb.createSheet("odd header- odd footer");
+ sheet3.createRow(10).createCell(0).setCellValue("Third sheet with oddHeader and oddFooter");
+ Header oddH = sheet3.getOddHeader();
+ //&C == centered
+ oddH.setCenter("centered oddHeader");
+ oddH.setLeft("left ");
+ oddH.setRight("right ");
+
+ Footer oddF = sheet3.getOddFooter();
+ oddF.setLeft("Page &P");
+ oddF.setRight("Pages &N ");
+
+ try (FileOutputStream fileOut = new FileOutputStream("headerFooter.xlsx")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/HyperlinkExample.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/HyperlinkExample.java
new file mode 100644
index 0000000000..519631960e
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/HyperlinkExample.java
@@ -0,0 +1,96 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.common.usermodel.HyperlinkType;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.CreationHelper;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.Hyperlink;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Demonstrates how to create hyperlinks.
+ */
+public class HyperlinkExample {
+
+ public static void main(String[]args) throws IOException {
+ try (Workbook wb = new XSSFWorkbook()) { //or new HSSFWorkbook();
+ CreationHelper createHelper = wb.getCreationHelper();
+
+ //cell style for hyperlinks
+ //by default hyperlinks are blue and underlined
+ CellStyle hlink_style = wb.createCellStyle();
+ Font hlink_font = wb.createFont();
+ hlink_font.setUnderline(Font.U_SINGLE);
+ hlink_font.setColor(IndexedColors.BLUE.getIndex());
+ hlink_style.setFont(hlink_font);
+
+ Cell cell;
+ Sheet sheet = wb.createSheet("Hyperlinks");
+ //URL
+ cell = sheet.createRow(0).createCell(0);
+ cell.setCellValue("URL Link");
+
+ Hyperlink link = createHelper.createHyperlink(HyperlinkType.URL);
+ link.setAddress("https://poi.apache.org/");
+ cell.setHyperlink(link);
+ cell.setCellStyle(hlink_style);
+
+ //link to a file in the current directory
+ cell = sheet.createRow(1).createCell(0);
+ cell.setCellValue("File Link");
+ link = createHelper.createHyperlink(HyperlinkType.FILE);
+ link.setAddress("link1.xls");
+ cell.setHyperlink(link);
+ cell.setCellStyle(hlink_style);
+
+ //e-mail link
+ cell = sheet.createRow(2).createCell(0);
+ cell.setCellValue("Email Link");
+ link = createHelper.createHyperlink(HyperlinkType.EMAIL);
+ //note, if subject contains white spaces, make sure they are url-encoded
+ link.setAddress("mailto:poi@apache.org?subject=Hyperlinks");
+ cell.setHyperlink(link);
+ cell.setCellStyle(hlink_style);
+
+ //link to a place in this workbook
+
+ //create a target sheet and cell
+ Sheet sheet2 = wb.createSheet("Target Sheet");
+ sheet2.createRow(0).createCell(0).setCellValue("Target Cell");
+
+ cell = sheet.createRow(3).createCell(0);
+ cell.setCellValue("Worksheet Link");
+ Hyperlink link2 = createHelper.createHyperlink(HyperlinkType.DOCUMENT);
+ link2.setAddress("'Target Sheet'!A1");
+ cell.setHyperlink(link2);
+ cell.setCellStyle(hlink_style);
+
+ try (FileOutputStream out = new FileOutputStream("hyperinks.xlsx")) {
+ wb.write(out);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/IterateCells.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/IterateCells.java
new file mode 100644
index 0000000000..0b49927977
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/IterateCells.java
@@ -0,0 +1,54 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Iterate over rows and cells
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class IterateCells {
+
+ private IterateCells() {}
+
+ public static void main(String[] args) throws IOException {
+ try (
+ FileInputStream is = new FileInputStream(args[0]);
+ Workbook wb = new XSSFWorkbook(is)
+ ) {
+ for (int i = 0; i < wb.getNumberOfSheets(); i++) {
+ Sheet sheet = wb.getSheetAt(i);
+ System.out.println(wb.getSheetName(i));
+ for (Row row : sheet) {
+ System.out.println("rownum: " + row.getRowNum());
+ for (Cell cell : row) {
+ System.out.println(cell);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/LineChart.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/LineChart.java
new file mode 100644
index 0000000000..724d3e2608
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/LineChart.java
@@ -0,0 +1,128 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xddf.usermodel.PresetColor;
+import org.apache.poi.xddf.usermodel.XDDFColor;
+import org.apache.poi.xddf.usermodel.XDDFLineProperties;
+import org.apache.poi.xddf.usermodel.XDDFShapeProperties;
+import org.apache.poi.xddf.usermodel.XDDFSolidFillProperties;
+import org.apache.poi.xddf.usermodel.chart.AxisCrosses;
+import org.apache.poi.xddf.usermodel.chart.AxisPosition;
+import org.apache.poi.xddf.usermodel.chart.ChartTypes;
+import org.apache.poi.xddf.usermodel.chart.LegendPosition;
+import org.apache.poi.xddf.usermodel.chart.MarkerStyle;
+import org.apache.poi.xddf.usermodel.chart.XDDFCategoryAxis;
+import org.apache.poi.xddf.usermodel.chart.XDDFChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
+import org.apache.poi.xddf.usermodel.chart.XDDFLineChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
+import org.apache.poi.xssf.usermodel.XSSFChart;
+import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
+import org.apache.poi.xssf.usermodel.XSSFDrawing;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Line chart example.
+ */
+public final class LineChart {
+ private LineChart() {}
+
+ public static void main(String[] args) throws IOException {
+ try (XSSFWorkbook wb = new XSSFWorkbook()) {
+ XSSFSheet sheet = wb.createSheet("linechart");
+ final int NUM_OF_ROWS = 3;
+ final int NUM_OF_COLUMNS = 10;
+
+ // Create a row and put some cells in it. Rows are 0 based.
+ Row row;
+ Cell cell;
+ for (int rowIndex = 0; rowIndex < NUM_OF_ROWS; rowIndex++) {
+ row = sheet.createRow((short) rowIndex);
+ for (int colIndex = 0; colIndex < NUM_OF_COLUMNS; colIndex++) {
+ cell = row.createCell((short) colIndex);
+ cell.setCellValue(colIndex * (rowIndex + 1.0));
+ }
+ }
+
+ XSSFDrawing drawing = sheet.createDrawingPatriarch();
+ XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 5, 10, 15);
+
+ XSSFChart chart = drawing.createChart(anchor);
+ XDDFChartLegend legend = chart.getOrAddLegend();
+ legend.setPosition(LegendPosition.TOP_RIGHT);
+
+ // Use a category axis for the bottom axis.
+ XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
+ bottomAxis.setTitle("x"); // https://stackoverflow.com/questions/32010765
+ XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
+ leftAxis.setTitle("f(x)");
+ leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
+
+ XDDFDataSource<Double> xs = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(0, 0, 0, NUM_OF_COLUMNS - 1));
+ XDDFNumericalDataSource<Double> ys1 = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(1, 1, 0, NUM_OF_COLUMNS - 1));
+ XDDFNumericalDataSource<Double> ys2 = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(2, 2, 0, NUM_OF_COLUMNS - 1));
+
+ XDDFLineChartData data = (XDDFLineChartData) chart.createData(ChartTypes.LINE, bottomAxis, leftAxis);
+ XDDFLineChartData.Series series1 = (XDDFLineChartData.Series) data.addSeries(xs, ys1);
+ series1.setTitle("2x", null); // https://stackoverflow.com/questions/21855842
+ series1.setSmooth(false); // https://stackoverflow.com/questions/29014848
+ series1.setMarkerStyle(MarkerStyle.STAR); // https://stackoverflow.com/questions/39636138
+ XDDFLineChartData.Series series2 = (XDDFLineChartData.Series) data.addSeries(xs, ys2);
+ series2.setTitle("3x", null);
+ series2.setSmooth(true);
+ series2.setMarkerSize((short) 6);
+ series2.setMarkerStyle(MarkerStyle.TRIANGLE); // https://stackoverflow.com/questions/39636138
+ chart.plot(data);
+
+ // if your series have missing values like https://stackoverflow.com/questions/29014848
+ // chart.displayBlanksAs(DisplayBlanks.GAP);
+
+ // https://stackoverflow.com/questions/24676460
+ solidLineSeries(data, 0, PresetColor.CHARTREUSE);
+ solidLineSeries(data, 1, PresetColor.TURQUOISE);
+
+ // Write the output to a file
+ try (FileOutputStream fileOut = new FileOutputStream("ooxml-line-chart.xlsx")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+
+ private static void solidLineSeries(XDDFChartData data, int index, PresetColor color) {
+ XDDFSolidFillProperties fill = new XDDFSolidFillProperties(XDDFColor.from(color));
+ XDDFLineProperties line = new XDDFLineProperties();
+ line.setFillProperties(fill);
+ XDDFChartData.Series series = data.getSeries(index);
+ XDDFShapeProperties properties = series.getShapeProperties();
+ if (properties == null) {
+ properties = new XDDFShapeProperties();
+ }
+ properties.setLineProperties(line);
+ series.setShapeProperties(properties);
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/LoadPasswordProtectedXlsx.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/LoadPasswordProtectedXlsx.java
new file mode 100644
index 0000000000..1ca5c34307
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/LoadPasswordProtectedXlsx.java
@@ -0,0 +1,83 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileInputStream;
+import java.io.InputStream;
+
+import org.apache.poi.examples.util.TempFileUtils;
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.poifs.crypt.Decryptor;
+import org.apache.poi.poifs.crypt.EncryptionInfo;
+import org.apache.poi.poifs.crypt.temp.AesZipFileZipEntrySource;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * An example that loads a password protected workbook and counts the sheets.
+ * <p><ul>
+ * <li>The example demonstrates that all temp files are removed.
+ * <li><code>AesZipFileZipEntrySource</code> is used to ensure that temp files are encrypted.
+ * </ul></p>
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class LoadPasswordProtectedXlsx {
+
+ private LoadPasswordProtectedXlsx() {}
+
+ public interface EncryptionHandler {
+ void handle(final InputStream inputStream) throws Exception;
+ }
+
+ public static void main(String[] args) throws Exception {
+ execute(args, LoadPasswordProtectedXlsx::printSheetCount);
+ }
+
+ public static void execute(String[] args, EncryptionHandler handler) throws Exception {
+ if(args.length != 2) {
+ throw new IllegalArgumentException("Expected 2 params: filename and password");
+ }
+ TempFileUtils.checkTempFiles();
+ String filename = args[0];
+ String password = args[1];
+ try (FileInputStream fis = new FileInputStream(filename);
+ POIFSFileSystem fs = new POIFSFileSystem(fis)) {
+ EncryptionInfo info = new EncryptionInfo(fs);
+ Decryptor d = Decryptor.getInstance(info);
+ if (!d.verifyPassword(password)) {
+ throw new RuntimeException("incorrect password");
+ }
+ try (InputStream unencryptedStream = d.getDataStream(fs)) {
+ handler.handle(unencryptedStream);
+ }
+ }
+ TempFileUtils.checkTempFiles();
+ }
+
+
+ private static void printSheetCount(final InputStream inputStream) throws Exception {
+ try (AesZipFileZipEntrySource source = AesZipFileZipEntrySource.createZipEntrySource(inputStream);
+ OPCPackage pkg = OPCPackage.open(source);
+ XSSFWorkbook workbook = new XSSFWorkbook(pkg)) {
+ System.out.println("sheet count: " + workbook.getNumberOfSheets());
+ }
+ }
+
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/MergingCells.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/MergingCells.java
new file mode 100644
index 0000000000..22695c53fe
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/MergingCells.java
@@ -0,0 +1,51 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xssf.usermodel.XSSFRichTextString;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * An example of how to merge regions of cells.
+ */
+public class MergingCells {
+ public static void main(String[] args) throws IOException {
+ try (Workbook wb = new XSSFWorkbook()) { //or new HSSFWorkbook();
+ Sheet sheet = wb.createSheet("new sheet");
+
+ Row row = sheet.createRow((short) 1);
+ Cell cell = row.createCell((short) 1);
+ cell.setCellValue(new XSSFRichTextString("This is a test of merging"));
+
+ sheet.addMergedRegion(new CellRangeAddress(1, 1, 1, 2));
+
+ // Write the output to a file
+ try (FileOutputStream fileOut = new FileOutputStream("merging_cells.xlsx")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/NewLinesInCells.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/NewLinesInCells.java
new file mode 100644
index 0000000000..8064260dd8
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/NewLinesInCells.java
@@ -0,0 +1,58 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * How to use newlines in cells
+ */
+public class NewLinesInCells {
+
+ public static void main(String[]args) throws IOException {
+ try (Workbook wb = new XSSFWorkbook()) { //or new HSSFWorkbook();
+ Sheet sheet = wb.createSheet();
+
+ Row row = sheet.createRow(2);
+ Cell cell = row.createCell(2);
+ cell.setCellValue("Use \n with word wrap on to create a new line");
+
+ //to enable newlines you need set a cell styles with wrap=true
+ CellStyle cs = wb.createCellStyle();
+ cs.setWrapText(true);
+ cell.setCellStyle(cs);
+
+ //increase row height to accommodate two lines of text
+ row.setHeightInPoints(2 * sheet.getDefaultRowHeightInPoints());
+
+ //adjust column width to fit the content
+ sheet.autoSizeColumn(2);
+
+ try (FileOutputStream fileOut = new FileOutputStream("ooxml-newlines.xlsx")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/Outlining.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/Outlining.java
new file mode 100644
index 0000000000..09f87cd5fa
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/Outlining.java
@@ -0,0 +1,78 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+public class Outlining {
+
+ public static void main(String[] args) throws IOException {
+ Outlining o=new Outlining();
+ o.groupRowColumn();
+ o.collapseExpandRowColumn();
+ }
+
+
+ private void groupRowColumn() throws IOException {
+ try (Workbook wb = new XSSFWorkbook()) {
+ Sheet sheet1 = wb.createSheet("new sheet");
+
+ sheet1.groupRow(5, 14);
+ sheet1.groupRow(7, 14);
+ sheet1.groupRow(16, 19);
+
+ sheet1.groupColumn((short) 4, (short) 7);
+ sheet1.groupColumn((short) 9, (short) 12);
+ sheet1.groupColumn((short) 10, (short) 11);
+
+ try (OutputStream fileOut = new FileOutputStream("outlining.xlsx")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+
+ private void collapseExpandRowColumn() throws IOException {
+ try (Workbook wb2 = new XSSFWorkbook()) {
+ Sheet sheet2 = wb2.createSheet("new sheet");
+ sheet2.groupRow(5, 14);
+ sheet2.groupRow(7, 14);
+ sheet2.groupRow(16, 19);
+
+ sheet2.groupColumn((short) 4, (short) 7);
+ sheet2.groupColumn((short) 9, (short) 12);
+ sheet2.groupColumn((short) 10, (short) 11);
+
+
+ sheet2.setRowGroupCollapsed(7, true);
+ //sheet1.setRowGroupCollapsed(7,false);
+
+ sheet2.setColumnGroupCollapsed((short) 4, true);
+ sheet2.setColumnGroupCollapsed((short) 4, false);
+
+ try (OutputStream fileOut = new FileOutputStream("outlining_collapsed.xlsx")) {
+ wb2.write(fileOut);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/ScatterChart.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/ScatterChart.java
new file mode 100644
index 0000000000..a5ce3c84ae
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/ScatterChart.java
@@ -0,0 +1,121 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xddf.usermodel.PresetColor;
+import org.apache.poi.xddf.usermodel.XDDFColor;
+import org.apache.poi.xddf.usermodel.XDDFLineProperties;
+import org.apache.poi.xddf.usermodel.XDDFShapeProperties;
+import org.apache.poi.xddf.usermodel.XDDFSolidFillProperties;
+import org.apache.poi.xddf.usermodel.chart.AxisCrosses;
+import org.apache.poi.xddf.usermodel.chart.AxisPosition;
+import org.apache.poi.xddf.usermodel.chart.ChartTypes;
+import org.apache.poi.xddf.usermodel.chart.LegendPosition;
+import org.apache.poi.xddf.usermodel.chart.XDDFChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
+import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFScatterChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
+import org.apache.poi.xssf.usermodel.XSSFChart;
+import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
+import org.apache.poi.xssf.usermodel.XSSFDrawing;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Illustrates how to create a simple scatter chart.
+ */
+public final class ScatterChart {
+ private ScatterChart() {}
+
+ public static void main(String[] args) throws IOException {
+ try (XSSFWorkbook wb = new XSSFWorkbook()) {
+ XSSFSheet sheet = wb.createSheet("Sheet 1");
+ final int NUM_OF_ROWS = 3;
+ final int NUM_OF_COLUMNS = 10;
+
+ // Create a row and put some cells in it. Rows are 0 based.
+ Row row;
+ Cell cell;
+ for (int rowIndex = 0; rowIndex < NUM_OF_ROWS; rowIndex++) {
+ row = sheet.createRow((short) rowIndex);
+ for (int colIndex = 0; colIndex < NUM_OF_COLUMNS; colIndex++) {
+ cell = row.createCell((short) colIndex);
+ cell.setCellValue(colIndex * (rowIndex + 1.0));
+ }
+ }
+
+ XSSFDrawing drawing = sheet.createDrawingPatriarch();
+ XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 5, 10, 15);
+
+ XSSFChart chart = drawing.createChart(anchor);
+ XDDFChartLegend legend = chart.getOrAddLegend();
+ legend.setPosition(LegendPosition.TOP_RIGHT);
+
+ XDDFValueAxis bottomAxis = chart.createValueAxis(AxisPosition.BOTTOM);
+ bottomAxis.setTitle("x"); // https://stackoverflow.com/questions/32010765
+ XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
+ leftAxis.setTitle("f(x)");
+ leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
+
+ XDDFDataSource<Double> xs = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(0, 0, 0, NUM_OF_COLUMNS - 1));
+ XDDFNumericalDataSource<Double> ys1 = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(1, 1, 0, NUM_OF_COLUMNS - 1));
+ XDDFNumericalDataSource<Double> ys2 = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(2, 2, 0, NUM_OF_COLUMNS - 1));
+
+
+ XDDFScatterChartData data = (XDDFScatterChartData) chart.createData(ChartTypes.SCATTER, bottomAxis, leftAxis);
+ XDDFScatterChartData.Series series1 = (XDDFScatterChartData.Series) data.addSeries(xs, ys1);
+ series1.setTitle("2x", null); // https://stackoverflow.com/questions/21855842
+ series1.setSmooth(false); // https://stackoverflow.com/questions/39636138
+ XDDFScatterChartData.Series series2 = (XDDFScatterChartData.Series) data.addSeries(xs, ys2);
+ series2.setTitle("3x", null);
+ chart.plot(data);
+
+ solidLineSeries(data, 0, PresetColor.CHARTREUSE);
+ solidLineSeries(data, 1, PresetColor.TURQUOISE);
+
+ // Write the output to a file
+ try (FileOutputStream fileOut = new FileOutputStream("ooxml-scatter-chart.xlsx")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+
+ private static void solidLineSeries(XDDFChartData data, int index, PresetColor color) {
+ XDDFSolidFillProperties fill = new XDDFSolidFillProperties(XDDFColor.from(color));
+ XDDFLineProperties line = new XDDFLineProperties();
+ line.setFillProperties(fill);
+ XDDFChartData.Series series = data.getSeries(index);
+ XDDFShapeProperties properties = series.getShapeProperties();
+ if (properties == null) {
+ properties = new XDDFShapeProperties();
+ }
+ properties.setLineProperties(line);
+ series.setShapeProperties(properties);
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/SelectedSheet.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/SelectedSheet.java
new file mode 100644
index 0000000000..ef6d9470c7
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/SelectedSheet.java
@@ -0,0 +1,45 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+public abstract class SelectedSheet {
+
+ public static void main(String[]args) throws IOException {
+ try (Workbook wb = new XSSFWorkbook()) { //or new HSSFWorkbook();
+
+ wb.createSheet("row sheet");
+ wb.createSheet("another sheet");
+ Sheet sheet3 = wb.createSheet(" sheet 3 ");
+ sheet3.setSelected(true);
+ wb.setActiveSheet(2);
+
+ // Create various cells and rows for spreadsheet.
+
+ try (FileOutputStream fileOut = new FileOutputStream("selectedSheet.xlsx")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/ShiftRows.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/ShiftRows.java
new file mode 100644
index 0000000000..92d1f4ce6d
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/ShiftRows.java
@@ -0,0 +1,60 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * How to shift rows up or down
+ */
+public class ShiftRows {
+
+ public static void main(String[]args) throws IOException {
+ try (Workbook wb = new XSSFWorkbook()) { //or new HSSFWorkbook();
+ Sheet sheet = wb.createSheet("Sheet1");
+
+ Row row1 = sheet.createRow(1);
+ row1.createCell(0).setCellValue(1);
+
+ Row row2 = sheet.createRow(4);
+ row2.createCell(1).setCellValue(2);
+
+ Row row3 = sheet.createRow(5);
+ row3.createCell(2).setCellValue(3);
+
+ Row row4 = sheet.createRow(6);
+ row4.createCell(3).setCellValue(4);
+
+ Row row5 = sheet.createRow(9);
+ row5.createCell(4).setCellValue(5);
+
+ // Shift rows 6 - 11 on the spreadsheet to the top (rows 0 - 5)
+ sheet.shiftRows(5, 10, -4);
+
+ try (FileOutputStream fileOut = new FileOutputStream("shiftRows.xlsx")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/SplitAndFreezePanes.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/SplitAndFreezePanes.java
new file mode 100644
index 0000000000..4a8afee879
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/SplitAndFreezePanes.java
@@ -0,0 +1,52 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * How to set split and freeze panes
+ */
+public class SplitAndFreezePanes {
+ public static void main(String[]args) throws IOException {
+ try (Workbook wb = new XSSFWorkbook()) {
+ Sheet sheet1 = wb.createSheet("new sheet");
+ Sheet sheet2 = wb.createSheet("second sheet");
+ Sheet sheet3 = wb.createSheet("third sheet");
+ Sheet sheet4 = wb.createSheet("fourth sheet");
+
+ // Freeze just one row
+ sheet1.createFreezePane(0, 1, 0, 1);
+ // Freeze just one column
+ sheet2.createFreezePane(1, 0, 1, 0);
+ // Freeze the columns and rows (forget about scrolling position of the lower right quadrant).
+ sheet3.createFreezePane(2, 2);
+ // Create a split with the lower left side being the active quadrant
+ sheet4.createSplitPane(2000, 2000, 0, 0, Sheet.PANE_LOWER_LEFT);
+
+ try (FileOutputStream fileOut = new FileOutputStream("splitFreezePane.xlsx")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/WorkbookProperties.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/WorkbookProperties.java
new file mode 100644
index 0000000000..9bb43f96fc
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/WorkbookProperties.java
@@ -0,0 +1,62 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.ooxml.POIXMLProperties;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * How to set extended and custom properties
+ */
+public class WorkbookProperties {
+
+ public static void main(String[]args) throws IOException {
+ try (XSSFWorkbook workbook = new XSSFWorkbook()) {
+ workbook.createSheet("Workbook Properties");
+
+ POIXMLProperties props = workbook.getProperties();
+
+ /*
+ * Extended properties are a predefined set of metadata properties
+ * that are specifically applicable to Office Open XML documents.
+ * Extended properties consist of 24 simple properties and 3 complex properties stored in the
+ * part targeted by the relationship of type
+ */
+ POIXMLProperties.ExtendedProperties ext = props.getExtendedProperties();
+ ext.getUnderlyingProperties().setCompany("Apache Software Foundation");
+ ext.getUnderlyingProperties().setTemplate("XSSF");
+
+ /*
+ * Custom properties enable users to define custom metadata properties.
+ */
+
+ POIXMLProperties.CustomProperties cust = props.getCustomProperties();
+ cust.addProperty("Author", "John Smith");
+ cust.addProperty("Year", 2009);
+ cust.addProperty("Price", 45.50);
+ cust.addProperty("Available", true);
+
+ try (FileOutputStream out = new FileOutputStream("workbook.xlsx")) {
+ workbook.write(out);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/WorkingWithBorders.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/WorkingWithBorders.java
new file mode 100644
index 0000000000..5ffa54aab8
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/WorkingWithBorders.java
@@ -0,0 +1,65 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Working with borders
+ */
+public class WorkingWithBorders {
+ public static void main(String[] args) throws IOException {
+ try (Workbook wb = new XSSFWorkbook()) { //or new HSSFWorkbook();
+ Sheet sheet = wb.createSheet("borders");
+
+ // Create a row and put some cells in it. Rows are 0 based.
+ Row row = sheet.createRow((short) 1);
+
+ // Create a cell and put a value in it.
+ Cell cell = row.createCell((short) 1);
+ cell.setCellValue(4);
+
+ // Style the cell with borders all around.
+ CellStyle style = wb.createCellStyle();
+ style.setBorderBottom(BorderStyle.THIN);
+ style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
+ style.setBorderLeft(BorderStyle.THIN);
+ style.setLeftBorderColor(IndexedColors.GREEN.getIndex());
+ style.setBorderRight(BorderStyle.THIN);
+ style.setRightBorderColor(IndexedColors.BLUE.getIndex());
+ style.setBorderTop(BorderStyle.MEDIUM_DASHED);
+ style.setTopBorderColor(IndexedColors.BLACK.getIndex());
+ cell.setCellStyle(style);
+
+ // Write the output to a file
+ try (FileOutputStream fileOut = new FileOutputStream("xssf-borders.xlsx")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/WorkingWithFonts.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/WorkingWithFonts.java
new file mode 100644
index 0000000000..a40ae57f42
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/WorkingWithFonts.java
@@ -0,0 +1,107 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Working with Fonts
+ */
+public class WorkingWithFonts {
+ public static void main(String[] args) throws IOException {
+ try (Workbook wb = new XSSFWorkbook()) { //or new HSSFWorkbook();
+ Sheet sheet = wb.createSheet("Fonts");
+
+ Font font0 = wb.createFont();
+ font0.setColor(IndexedColors.BROWN.getIndex());
+ CellStyle style0 = wb.createCellStyle();
+ style0.setFont(font0);
+
+ Font font1 = wb.createFont();
+ font1.setFontHeightInPoints((short) 14);
+ font1.setFontName("Courier New");
+ font1.setColor(IndexedColors.RED.getIndex());
+ CellStyle style1 = wb.createCellStyle();
+ style1.setFont(font1);
+
+ Font font2 = wb.createFont();
+ font2.setFontHeightInPoints((short) 16);
+ font2.setFontName("Arial");
+ font2.setColor(IndexedColors.GREEN.getIndex());
+ CellStyle style2 = wb.createCellStyle();
+ style2.setFont(font2);
+
+ Font font3 = wb.createFont();
+ font3.setFontHeightInPoints((short) 18);
+ font3.setFontName("Times New Roman");
+ font3.setColor(IndexedColors.LAVENDER.getIndex());
+ CellStyle style3 = wb.createCellStyle();
+ style3.setFont(font3);
+
+ Font font4 = wb.createFont();
+ font4.setFontHeightInPoints((short) 18);
+ font4.setFontName("Wingdings");
+ font4.setColor(IndexedColors.GOLD.getIndex());
+ CellStyle style4 = wb.createCellStyle();
+ style4.setFont(font4);
+
+ Font font5 = wb.createFont();
+ font5.setFontName("Symbol");
+ CellStyle style5 = wb.createCellStyle();
+ style5.setFont(font5);
+
+ Cell cell0 = sheet.createRow(0).createCell(1);
+ cell0.setCellValue("Default");
+ cell0.setCellStyle(style0);
+
+ Cell cell1 = sheet.createRow(1).createCell(1);
+ cell1.setCellValue("Courier");
+ cell1.setCellStyle(style1);
+
+ Cell cell2 = sheet.createRow(2).createCell(1);
+ cell2.setCellValue("Arial");
+ cell2.setCellStyle(style2);
+
+ Cell cell3 = sheet.createRow(3).createCell(1);
+ cell3.setCellValue("Times New Roman");
+ cell3.setCellStyle(style3);
+
+ Cell cell4 = sheet.createRow(4).createCell(1);
+ cell4.setCellValue("Wingdings");
+ cell4.setCellStyle(style4);
+
+ Cell cell5 = sheet.createRow(5).createCell(1);
+ cell5.setCellValue("Symbol");
+ cell5.setCellStyle(style5);
+
+ // Write the output to a file
+ try (FileOutputStream fileOut = new FileOutputStream("xssf-fonts.xlsx")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/WorkingWithPageSetup.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/WorkingWithPageSetup.java
new file mode 100644
index 0000000000..a43c5125a3
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/WorkingWithPageSetup.java
@@ -0,0 +1,82 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Demonstrates various settings avaiable in the Page Setup dialog
+ */
+public class WorkingWithPageSetup {
+
+ public static void main(String[]args) throws Exception {
+ try (Workbook wb = new XSSFWorkbook()) { //or new HSSFWorkbook();
+
+ /*
+ * It's possible to set up repeating rows and columns in your printouts by using the setRepeatingRowsAndColumns() function in the Workbook object.
+ *
+ * This function Contains 5 parameters:
+ * The first parameter is the index to the sheet (0 = first sheet).
+ * The second and third parameters specify the range for the columns to repreat.
+ * To stop the columns from repeating pass in -1 as the start and end column.
+ * The fourth and fifth parameters specify the range for the rows to repeat.
+ * To stop the columns from repeating pass in -1 as the start and end rows.
+ */
+ Sheet sheet1 = wb.createSheet("new sheet");
+ Sheet sheet2 = wb.createSheet("second sheet");
+
+ // Set the columns to repeat from column 0 to 2 on the first sheet
+ Row row1 = sheet1.createRow(0);
+ row1.createCell(0).setCellValue(1);
+ row1.createCell(1).setCellValue(2);
+ row1.createCell(2).setCellValue(3);
+ Row row2 = sheet1.createRow(1);
+ row2.createCell(1).setCellValue(4);
+ row2.createCell(2).setCellValue(5);
+
+
+ Row row3 = sheet2.createRow(1);
+ row3.createCell(0).setCellValue(2.1);
+ row3.createCell(4).setCellValue(2.2);
+ row3.createCell(5).setCellValue(2.3);
+ Row row4 = sheet2.createRow(2);
+ row4.createCell(4).setCellValue(2.4);
+ row4.createCell(5).setCellValue(2.5);
+
+ // Set the columns to repeat from column 0 to 2 on the first sheet
+ sheet1.setRepeatingColumns(CellRangeAddress.valueOf("A:C"));
+ // Set the the repeating rows and columns on the second sheet.
+ CellRangeAddress cra = CellRangeAddress.valueOf("E2:F3");
+ sheet2.setRepeatingColumns(cra);
+ sheet2.setRepeatingRows(cra);
+
+ //set the print area for the first sheet
+ wb.setPrintArea(0, 1, 2, 0, 3);
+
+
+ try (FileOutputStream fileOut = new FileOutputStream("xssf-printsetup.xlsx")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/WorkingWithPictures.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/WorkingWithPictures.java
new file mode 100644
index 0000000000..555bc513d8
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/WorkingWithPictures.java
@@ -0,0 +1,79 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.poi.ss.usermodel.ClientAnchor;
+import org.apache.poi.ss.usermodel.CreationHelper;
+import org.apache.poi.ss.usermodel.Drawing;
+import org.apache.poi.ss.usermodel.Picture;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Demonstrates how to insert pictures in a SpreadsheetML document
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class WorkingWithPictures {
+ private WorkingWithPictures() {}
+
+ public static void main(String[] args) throws IOException {
+
+ //create a new workbook
+ try (Workbook wb = new XSSFWorkbook()) {
+ CreationHelper helper = wb.getCreationHelper();
+
+ //add a picture in this workbook.
+ InputStream is = new FileInputStream(args[0]);
+ byte[] bytes = IOUtils.toByteArray(is);
+ is.close();
+ int pictureIdx = wb.addPicture(bytes, Workbook.PICTURE_TYPE_JPEG);
+
+ //create sheet
+ Sheet sheet = wb.createSheet();
+
+ //create drawing
+ Drawing<?> drawing = sheet.createDrawingPatriarch();
+
+ //add a picture shape
+ ClientAnchor anchor = helper.createClientAnchor();
+ anchor.setCol1(1);
+ anchor.setRow1(1);
+ Picture pict = drawing.createPicture(anchor, pictureIdx);
+
+ //auto-size picture
+ pict.resize(2);
+
+ //save workbook
+ String file = "picture.xls";
+ if (wb instanceof XSSFWorkbook) {
+ file += "x"; // NOSONAR
+ }
+ try (OutputStream fileOut = new FileOutputStream(file)) {
+ wb.write(fileOut);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/WorkingWithRichText.java b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/WorkingWithRichText.java
new file mode 100644
index 0000000000..43376fa1f6
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xssf/usermodel/WorkingWithRichText.java
@@ -0,0 +1,70 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.examples.xssf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.xssf.usermodel.XSSFCell;
+import org.apache.poi.xssf.usermodel.XSSFColor;
+import org.apache.poi.xssf.usermodel.XSSFFont;
+import org.apache.poi.xssf.usermodel.XSSFRichTextString;
+import org.apache.poi.xssf.usermodel.XSSFRow;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+/**
+ * Demonstrates how to work with rich text
+ */
+public final class WorkingWithRichText {
+
+ private WorkingWithRichText() {}
+
+ public static void main(String[] args) throws Exception {
+ try (XSSFWorkbook wb = new XSSFWorkbook()) {
+ XSSFSheet sheet = wb.createSheet();
+ XSSFRow row = sheet.createRow(2);
+
+ XSSFCell cell = row.createCell(1);
+ XSSFRichTextString rt = new XSSFRichTextString("The quick brown fox");
+
+ XSSFFont font1 = wb.createFont();
+ font1.setBold(true);
+ font1.setColor(new XSSFColor(new java.awt.Color(255, 0, 0), wb.getStylesSource().getIndexedColors()));
+ rt.applyFont(0, 10, font1);
+
+ XSSFFont font2 = wb.createFont();
+ font2.setItalic(true);
+ font2.setUnderline(Font.U_DOUBLE);
+ font2.setColor(new XSSFColor(new java.awt.Color(0, 255, 0), wb.getStylesSource().getIndexedColors()));
+ rt.applyFont(10, 19, font2);
+
+ XSSFFont font3 = wb.createFont();
+ font3.setColor(new XSSFColor(new java.awt.Color(0, 0, 255), wb.getStylesSource().getIndexedColors()));
+ rt.append(" Jumped over the lazy dog", font3);
+
+ cell.setCellValue(rt);
+
+ // Write the output to a file
+ try (OutputStream fileOut = new FileOutputStream("xssf-richtext.xlsx")) {
+ wb.write(fileOut);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/BarChartExample.java b/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/BarChartExample.java
new file mode 100644
index 0000000000..d26907c30e
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/BarChartExample.java
@@ -0,0 +1,145 @@
+
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.xwpf.usermodel;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xddf.usermodel.chart.AxisOrientation;
+import org.apache.poi.xddf.usermodel.chart.AxisPosition;
+import org.apache.poi.xddf.usermodel.chart.BarDirection;
+import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
+import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
+import org.apache.poi.xwpf.usermodel.XWPFChart;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+
+/**
+ * Build a bar chart from a template docx
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class BarChartExample {
+ private BarChartExample() {}
+
+ private static void usage(){
+ System.out.println("Usage: BarChartExample <bar-chart-template.docx> <bar-chart-data.txt>");
+ System.out.println(" bar-chart-template.docx template with a bar chart");
+ System.out.println(" bar-chart-data.txt the model to set. First line is chart title, " +
+ "then go pairs {axis-label value}");
+ }
+
+ public static void main(String[] args) throws Exception {
+ if(args.length < 2) {
+ usage();
+ return;
+ }
+
+ try (FileInputStream argIS = new FileInputStream(args[0]);
+ BufferedReader modelReader = Files.newBufferedReader(Paths.get(args[1]), StandardCharsets.UTF_8)) {
+
+ String chartTitle = modelReader.readLine(); // first line is chart title
+ String[] series = modelReader.readLine().split(",");
+
+ // Category Axis Data
+ List<String> listLanguages = new ArrayList<>(10);
+
+ // Values
+ List<Double> listCountries = new ArrayList<>(10);
+ List<Double> listSpeakers = new ArrayList<>(10);
+
+ // set model
+ String ln;
+ while((ln = modelReader.readLine()) != null) {
+ String[] vals = ln.split(",");
+ listCountries.add(Double.valueOf(vals[0]));
+ listSpeakers.add(Double.valueOf(vals[1]));
+ listLanguages.add(vals[2]);
+ }
+ String[] categories = listLanguages.toArray(new String[0]);
+ Double[] values1 = listCountries.toArray(new Double[0]);
+ Double[] values2 = listSpeakers.toArray(new Double[0]);
+
+ try (XWPFDocument doc = new XWPFDocument(argIS)) {
+ XWPFChart chart = doc.getCharts().get(0);
+ setBarData(chart, chartTitle, series, categories, values1, values2);
+ chart = doc.getCharts().get(1);
+ setColumnData(chart, "Column variant");
+
+ // save the result
+ try (OutputStream out = new FileOutputStream("bar-chart-demo-output.docx")) {
+ doc.write(out);
+ }
+ }
+ }
+ System.out.println("Done");
+ }
+
+ private static void setBarData(XWPFChart chart, String chartTitle, String[] series, String[] categories, Double[] values1, Double[] values2) {
+ final List<XDDFChartData> data = chart.getChartSeries();
+ final XDDFBarChartData bar = (XDDFBarChartData) data.get(0);
+
+ final int numOfPoints = categories.length;
+ final String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0));
+ final String valuesDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 1, 1));
+ final String valuesDataRange2 = chart.formatRange(new CellRangeAddress(1, numOfPoints, 2, 2));
+ final XDDFDataSource<?> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, 0);
+ final XDDFNumericalDataSource<? extends Number> valuesData = XDDFDataSourcesFactory.fromArray(values1, valuesDataRange, 1);
+ values1[6] = 16.0; // if you ever want to change the underlying data
+ final XDDFNumericalDataSource<? extends Number> valuesData2 = XDDFDataSourcesFactory.fromArray(values2, valuesDataRange2, 2);
+
+ XDDFChartData.Series series1 = bar.getSeries(0);
+ series1.replaceData(categoriesData, valuesData);
+ series1.setTitle(series[0], chart.setSheetTitle(series[0], 0));
+ XDDFChartData.Series series2 = bar.addSeries(categoriesData, valuesData2);
+ series2.setTitle(series[1], chart.setSheetTitle(series[1], 1));
+
+ chart.plot(bar);
+ chart.setTitleText(chartTitle); // https://stackoverflow.com/questions/30532612
+ chart.setTitleOverlay(false);
+ }
+
+ private static void setColumnData(XWPFChart chart, String chartTitle) {
+ // Series Text
+ List<XDDFChartData> series = chart.getChartSeries();
+ XDDFBarChartData bar = (XDDFBarChartData) series.get(0);
+
+ // in order to transform a bar chart into a column chart, you just need to change the bar direction
+ bar.setBarDirection(BarDirection.COL);
+
+ // looking for "Stacked Bar Chart"? uncomment the following line
+ // bar.setBarGrouping(BarGrouping.STACKED);
+
+ // additionally, you can adjust the axes
+ bar.getCategoryAxis().setOrientation(AxisOrientation.MAX_MIN);
+ bar.getValueAxes().get(0).setPosition(AxisPosition.TOP);
+ }
+}
+
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/BetterHeaderFooterExample.java b/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/BetterHeaderFooterExample.java
new file mode 100644
index 0000000000..39c9d0812e
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/BetterHeaderFooterExample.java
@@ -0,0 +1,56 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.xwpf.usermodel;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.poi.wp.usermodel.HeaderFooterType;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.apache.poi.xwpf.usermodel.XWPFFooter;
+import org.apache.poi.xwpf.usermodel.XWPFHeader;
+import org.apache.poi.xwpf.usermodel.XWPFParagraph;
+import org.apache.poi.xwpf.usermodel.XWPFRun;
+
+public class BetterHeaderFooterExample {
+
+ public static void main(String[] args) throws IOException {
+ try (XWPFDocument doc = new XWPFDocument()) {
+
+ XWPFParagraph p = doc.createParagraph();
+
+ XWPFRun r = p.createRun();
+ r.setText("Some Text");
+ r.setBold(true);
+ r = p.createRun();
+ r.setText("Goodbye");
+
+ // create header/footer functions insert an empty paragraph
+ XWPFHeader head = doc.createHeader(HeaderFooterType.DEFAULT);
+ head.createParagraph().createRun().setText("header");
+
+ XWPFFooter foot = doc.createFooter(HeaderFooterType.DEFAULT);
+ foot.createParagraph().createRun().setText("footer");
+
+ try (OutputStream os = new FileOutputStream(new File("header2.docx"))) {
+ doc.write(os);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/ChartFromScratch.java b/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/ChartFromScratch.java
new file mode 100644
index 0000000000..889ff30fb1
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/ChartFromScratch.java
@@ -0,0 +1,154 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.xwpf.usermodel;
+
+import java.io.BufferedReader;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xddf.usermodel.chart.AxisCrossBetween;
+import org.apache.poi.xddf.usermodel.chart.AxisCrosses;
+import org.apache.poi.xddf.usermodel.chart.AxisPosition;
+import org.apache.poi.xddf.usermodel.chart.AxisTickMark;
+import org.apache.poi.xddf.usermodel.chart.BarDirection;
+import org.apache.poi.xddf.usermodel.chart.BarGrouping;
+import org.apache.poi.xddf.usermodel.chart.ChartTypes;
+import org.apache.poi.xddf.usermodel.chart.LegendPosition;
+import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData;
+import org.apache.poi.xddf.usermodel.chart.XDDFChart;
+import org.apache.poi.xddf.usermodel.chart.XDDFChartAxis;
+import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
+import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
+import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
+import org.apache.poi.xwpf.usermodel.XWPFChart;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+
+/**
+ * Build a chart without reading template file
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class ChartFromScratch {
+ private ChartFromScratch() {}
+
+ private static void usage(){
+ System.out.println("Usage: ChartFromScratch <bar-chart-data.txt>");
+ System.out.println(" bar-chart-data.txt the model to set. First line is chart title, " +
+ "then go pairs {axis-label value}");
+ }
+
+ public static void main(String[] args) throws Exception {
+ if(args.length < 1) {
+ usage();
+ return;
+ }
+
+ try (BufferedReader modelReader = Files.newBufferedReader(Paths.get(args[0]), StandardCharsets.UTF_8)) {
+
+ String chartTitle = modelReader.readLine(); // first line is chart title
+ String[] series = modelReader.readLine().split(",");
+
+ // Category Axis Data
+ List<String> listLanguages = new ArrayList<>(10);
+
+ // Values
+ List<Double> listCountries = new ArrayList<>(10);
+ List<Double> listSpeakers = new ArrayList<>(10);
+
+ // set model
+ String ln;
+ while((ln = modelReader.readLine()) != null) {
+ String[] vals = ln.split(",");
+ listCountries.add(Double.valueOf(vals[0]));
+ listSpeakers.add(Double.valueOf(vals[1]));
+ listLanguages.add(vals[2]);
+ }
+
+ String[] categories = listLanguages.toArray(new String[0]);
+ Double[] values1 = listCountries.toArray(new Double[0]);
+ Double[] values2 = listSpeakers.toArray(new Double[0]);
+
+ try (XWPFDocument doc = new XWPFDocument();
+ OutputStream out = new FileOutputStream("chart-from-scratch.docx")) {
+ XWPFChart chart = doc.createChart(XDDFChart.DEFAULT_WIDTH * 10, XDDFChart.DEFAULT_HEIGHT * 15);
+ setBarData(chart, chartTitle, series, categories, values1, values2);
+ // save the result
+ doc.write(out);
+ }
+ }
+ System.out.println("Done");
+ }
+
+ private static void setBarData(XWPFChart chart, String chartTitle, String[] series, String[] categories, Double[] values1, Double[] values2) {
+ // Use a category axis for the bottom axis.
+ XDDFChartAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
+ bottomAxis.setTitle(series[2]);
+ XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
+ leftAxis.setTitle(series[0]+","+series[1]);
+ leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
+ leftAxis.setMajorTickMark(AxisTickMark.OUT);
+ leftAxis.setCrossBetween(AxisCrossBetween.BETWEEN);
+
+ final int numOfPoints = categories.length;
+ final String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, COLUMN_LANGUAGES, COLUMN_LANGUAGES));
+ final String valuesDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, COLUMN_COUNTRIES, COLUMN_COUNTRIES));
+ final String valuesDataRange2 = chart.formatRange(new CellRangeAddress(1, numOfPoints, COLUMN_SPEAKERS, COLUMN_SPEAKERS));
+ final XDDFDataSource<?> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, COLUMN_LANGUAGES);
+ final XDDFNumericalDataSource<? extends Number> valuesData = XDDFDataSourcesFactory.fromArray(values1, valuesDataRange, COLUMN_COUNTRIES);
+ valuesData.setFormatCode("General");
+ values1[6] = 16.0; // if you ever want to change the underlying data, it has to be done before building the data source
+ final XDDFNumericalDataSource<? extends Number> valuesData2 = XDDFDataSourcesFactory.fromArray(values2, valuesDataRange2, COLUMN_SPEAKERS);
+ valuesData2.setFormatCode("General");
+
+
+ XDDFBarChartData bar = (XDDFBarChartData) chart.createData(ChartTypes.BAR, bottomAxis, leftAxis);
+ bar.setBarGrouping(BarGrouping.CLUSTERED);
+
+ XDDFBarChartData.Series series1 = (XDDFBarChartData.Series) bar.addSeries(categoriesData, valuesData);
+ series1.setTitle(series[0], chart.setSheetTitle(series[0], COLUMN_COUNTRIES));
+
+ XDDFBarChartData.Series series2 = (XDDFBarChartData.Series) bar.addSeries(categoriesData, valuesData2);
+ series2.setTitle(series[1], chart.setSheetTitle(series[1], COLUMN_SPEAKERS));
+
+ bar.setVaryColors(true);
+ bar.setBarDirection(BarDirection.COL);
+ chart.plot(bar);
+
+ XDDFChartLegend legend = chart.getOrAddLegend();
+ legend.setPosition(LegendPosition.LEFT);
+ legend.setOverlay(false);
+
+ chart.setTitleText(chartTitle);
+ chart.setTitleOverlay(false);
+ chart.setAutoTitleDeleted(false);
+ }
+
+ private static final int COLUMN_LANGUAGES = 0;
+ private static final int COLUMN_COUNTRIES = 1;
+ private static final int COLUMN_SPEAKERS = 2;
+}
+
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/HeaderFooterTable.java b/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/HeaderFooterTable.java
new file mode 100644
index 0000000000..70d2b7e588
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/HeaderFooterTable.java
@@ -0,0 +1,105 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.xwpf.usermodel;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.math.BigInteger;
+
+import org.apache.poi.wp.usermodel.HeaderFooterType;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.apache.poi.xwpf.usermodel.XWPFFooter;
+import org.apache.poi.xwpf.usermodel.XWPFHeader;
+import org.apache.poi.xwpf.usermodel.XWPFParagraph;
+import org.apache.poi.xwpf.usermodel.XWPFRun;
+import org.apache.poi.xwpf.usermodel.XWPFTable;
+import org.apache.poi.xwpf.usermodel.XWPFTableCell;
+import org.apache.poi.xwpf.usermodel.XWPFTableRow;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblGrid;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblGridCol;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblLayoutType;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblPr;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTblLayoutType;
+
+public class HeaderFooterTable {
+
+ public static void main(String[] args) throws IOException {
+ try (XWPFDocument doc = new XWPFDocument()) {
+
+ // Create a header with a 1 row, 3 column table
+ // changes made for issue 57366 allow a new header or footer
+ // to be created empty. This is a change. You will have to add
+ // either a paragraph or a table to the header or footer for
+ // the document to be considered valid.
+ XWPFHeader hdr = doc.createHeader(HeaderFooterType.DEFAULT);
+ XWPFTable tbl = hdr.createTable(1, 3);
+
+ // Set the padding around text in the cells to 1/10th of an inch
+ int pad = (int) (.1 * 1440);
+ tbl.setCellMargins(pad, pad, pad, pad);
+
+ // Set table width to 6.5 inches in 1440ths of a point
+ tbl.setWidth((int) (6.5 * 1440));
+ // Can not yet set table or cell width properly, tables default to
+ // autofit layout, and this requires fixed layout
+ CTTbl ctTbl = tbl.getCTTbl();
+ CTTblPr ctTblPr = ctTbl.addNewTblPr();
+ CTTblLayoutType layoutType = ctTblPr.addNewTblLayout();
+ layoutType.setType(STTblLayoutType.FIXED);
+
+ // Now set up a grid for the table, cells will fit into the grid
+ // Each cell width is 3120 in 1440ths of an inch, or 1/3rd of 6.5"
+ BigInteger w = new BigInteger("3120");
+ CTTblGrid grid = ctTbl.addNewTblGrid();
+ for (int i = 0; i < 3; i++) {
+ CTTblGridCol gridCol = grid.addNewGridCol();
+ gridCol.setW(w);
+ }
+
+ // Add paragraphs to the cells
+ XWPFTableRow row = tbl.getRow(0);
+ XWPFTableCell cell = row.getCell(0);
+ XWPFParagraph p = cell.getParagraphArray(0);
+ XWPFRun r = p.createRun();
+ r.setText("header left cell");
+
+ cell = row.getCell(1);
+ p = cell.getParagraphArray(0);
+ r = p.createRun();
+ r.setText("header center cell");
+
+ cell = row.getCell(2);
+ p = cell.getParagraphArray(0);
+ r = p.createRun();
+ r.setText("header right cell");
+
+ // Create a footer with a Paragraph
+ XWPFFooter ftr = doc.createFooter(HeaderFooterType.DEFAULT);
+ p = ftr.createParagraph();
+
+ r = p.createRun();
+ r.setText("footer text");
+
+ try (OutputStream os = new FileOutputStream(new File("headertable.docx"))) {
+ doc.write(os);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/SimpleDocument.java b/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/SimpleDocument.java
new file mode 100644
index 0000000000..57515545cf
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/SimpleDocument.java
@@ -0,0 +1,136 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.xwpf.usermodel;
+
+import java.io.FileOutputStream;
+
+import org.apache.poi.xwpf.usermodel.Borders;
+import org.apache.poi.xwpf.usermodel.BreakClear;
+import org.apache.poi.xwpf.usermodel.BreakType;
+import org.apache.poi.xwpf.usermodel.LineSpacingRule;
+import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
+import org.apache.poi.xwpf.usermodel.TextAlignment;
+import org.apache.poi.xwpf.usermodel.UnderlinePatterns;
+import org.apache.poi.xwpf.usermodel.VerticalAlign;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.apache.poi.xwpf.usermodel.XWPFHyperlinkRun;
+import org.apache.poi.xwpf.usermodel.XWPFParagraph;
+import org.apache.poi.xwpf.usermodel.XWPFRun;
+
+/**
+ * A simple WOrdprocessingML document created by POI XWPF API
+ */
+public class SimpleDocument {
+
+ public static void main(String[] args) throws Exception {
+ try (XWPFDocument doc = new XWPFDocument()) {
+
+ XWPFParagraph p1 = doc.createParagraph();
+ p1.setAlignment(ParagraphAlignment.CENTER);
+ p1.setBorderBottom(Borders.DOUBLE);
+ p1.setBorderTop(Borders.DOUBLE);
+
+ p1.setBorderRight(Borders.DOUBLE);
+ p1.setBorderLeft(Borders.DOUBLE);
+ p1.setBorderBetween(Borders.SINGLE);
+
+ p1.setVerticalAlignment(TextAlignment.TOP);
+
+ XWPFRun r1 = p1.createRun();
+ r1.setBold(true);
+ r1.setText("The quick brown fox");
+ r1.setBold(true);
+ r1.setFontFamily("Courier");
+ r1.setUnderline(UnderlinePatterns.DOT_DOT_DASH);
+ r1.setTextPosition(100);
+
+ XWPFParagraph p2 = doc.createParagraph();
+ p2.setAlignment(ParagraphAlignment.RIGHT);
+
+ //BORDERS
+ p2.setBorderBottom(Borders.DOUBLE);
+ p2.setBorderTop(Borders.DOUBLE);
+ p2.setBorderRight(Borders.DOUBLE);
+ p2.setBorderLeft(Borders.DOUBLE);
+ p2.setBorderBetween(Borders.SINGLE);
+
+ XWPFRun r2 = p2.createRun();
+ r2.setText("jumped over the lazy dog");
+ r2.setStrikeThrough(true);
+ r2.setFontSize(20);
+
+ XWPFRun r3 = p2.createRun();
+ r3.setText("and went away");
+ r3.setStrikeThrough(true);
+ r3.setFontSize(20);
+ r3.setSubscript(VerticalAlign.SUPERSCRIPT);
+
+ // hyperlink
+ XWPFHyperlinkRun hyperlink = p2.insertNewHyperlinkRun(0, "http://poi.apache.org/");
+ hyperlink.setUnderline(UnderlinePatterns.SINGLE);
+ hyperlink.setColor("0000ff");
+ hyperlink.setText("Apache POI");
+
+ XWPFParagraph p3 = doc.createParagraph();
+ p3.setWordWrapped(true);
+ p3.setPageBreak(true);
+
+ //p3.setAlignment(ParagraphAlignment.DISTRIBUTE);
+ p3.setAlignment(ParagraphAlignment.BOTH);
+ p3.setSpacingBetween(15, LineSpacingRule.EXACT);
+
+ p3.setIndentationFirstLine(600);
+
+
+ XWPFRun r4 = p3.createRun();
+ r4.setTextPosition(20);
+ r4.setText("To be, or not to be: that is the question: "
+ + "Whether 'tis nobler in the mind to suffer "
+ + "The slings and arrows of outrageous fortune, "
+ + "Or to take arms against a sea of troubles, "
+ + "And by opposing end them? To die: to sleep; ");
+ r4.addBreak(BreakType.PAGE);
+ r4.setText("No more; and by a sleep to say we end "
+ + "The heart-ache and the thousand natural shocks "
+ + "That flesh is heir to, 'tis a consummation "
+ + "Devoutly to be wish'd. To die, to sleep; "
+ + "To sleep: perchance to dream: ay, there's the rub; "
+ + ".......");
+ r4.setItalic(true);
+//This would imply that this break shall be treated as a simple line break, and break the line after that word:
+
+ XWPFRun r5 = p3.createRun();
+ r5.setTextPosition(-10);
+ r5.setText("For in that sleep of death what dreams may come");
+ r5.addCarriageReturn();
+ r5.setText("When we have shuffled off this mortal coil, "
+ + "Must give us pause: there's the respect "
+ + "That makes calamity of so long life;");
+ r5.addBreak();
+ r5.setText("For who would bear the whips and scorns of time, "
+ + "The oppressor's wrong, the proud man's contumely,");
+
+ r5.addBreak(BreakClear.ALL);
+ r5.setText("The pangs of despised love, the law's delay, "
+ + "The insolence of office and the spurns " + ".......");
+
+ try (FileOutputStream out = new FileOutputStream("simple.docx")) {
+ doc.write(out);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/SimpleDocumentWithHeader.java b/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/SimpleDocumentWithHeader.java
new file mode 100644
index 0000000000..659f6b6f39
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/SimpleDocumentWithHeader.java
@@ -0,0 +1,70 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.xwpf.usermodel;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.apache.poi.xwpf.usermodel.XWPFParagraph;
+import org.apache.poi.xwpf.usermodel.XWPFRun;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTText;
+
+/**
+ *
+ * @author Richard Ngo
+ *
+ */
+public class SimpleDocumentWithHeader {
+
+ public static void main(String[] args) throws IOException {
+ try (XWPFDocument doc = new XWPFDocument()) {
+
+ XWPFParagraph p = doc.createParagraph();
+
+ XWPFRun r = p.createRun();
+ r.setText("Some Text");
+ r.setBold(true);
+ r = p.createRun();
+ r.setText("Goodbye");
+
+ CTP ctP = CTP.Factory.newInstance();
+ CTText t = ctP.addNewR().addNewT();
+ t.setStringValue("header");
+ XWPFParagraph[] pars = new XWPFParagraph[1];
+ p = new XWPFParagraph(ctP, doc);
+ pars[0] = p;
+
+ XWPFHeaderFooterPolicy hfPolicy = doc.createHeaderFooterPolicy();
+ hfPolicy.createHeader(XWPFHeaderFooterPolicy.DEFAULT, pars);
+
+ ctP = CTP.Factory.newInstance();
+ t = ctP.addNewR().addNewT();
+ t.setStringValue("My Footer");
+ pars[0] = new XWPFParagraph(ctP, doc);
+ hfPolicy.createFooter(XWPFHeaderFooterPolicy.DEFAULT, pars);
+
+ try (OutputStream os = new FileOutputStream(new File("header.docx"))) {
+ doc.write(os);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/SimpleImages.java b/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/SimpleImages.java
new file mode 100644
index 0000000000..1f996cfd1f
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/SimpleImages.java
@@ -0,0 +1,93 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+package org.apache.poi.examples.xwpf.usermodel;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.util.Units;
+import org.apache.poi.xwpf.usermodel.BreakType;
+import org.apache.poi.xwpf.usermodel.Document;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.apache.poi.xwpf.usermodel.XWPFParagraph;
+import org.apache.poi.xwpf.usermodel.XWPFRun;
+
+/**
+ * Demonstrates how to add pictures in a .docx document
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public final class SimpleImages {
+
+ private SimpleImages() {}
+
+ public static void main(String[] args) throws IOException, InvalidFormatException {
+ try (XWPFDocument doc = new XWPFDocument()) {
+ XWPFParagraph p = doc.createParagraph();
+
+ XWPFRun r = p.createRun();
+
+ for (String imgFile : args) {
+ int format;
+
+ if (imgFile.endsWith(".emf")) {
+ format = Document.PICTURE_TYPE_EMF;
+ } else if (imgFile.endsWith(".wmf")) {
+ format = Document.PICTURE_TYPE_WMF;
+ } else if (imgFile.endsWith(".pict")) {
+ format = Document.PICTURE_TYPE_PICT;
+ } else if (imgFile.endsWith(".jpeg") || imgFile.endsWith(".jpg")) {
+ format = Document.PICTURE_TYPE_JPEG;
+ } else if (imgFile.endsWith(".png")) {
+ format = Document.PICTURE_TYPE_PNG;
+ } else if (imgFile.endsWith(".dib")) {
+ format = Document.PICTURE_TYPE_DIB;
+ } else if (imgFile.endsWith(".gif")) {
+ format = Document.PICTURE_TYPE_GIF;
+ } else if (imgFile.endsWith(".tiff")) {
+ format = Document.PICTURE_TYPE_TIFF;
+ } else if (imgFile.endsWith(".eps")) {
+ format = Document.PICTURE_TYPE_EPS;
+ } else if (imgFile.endsWith(".bmp")) {
+ format = Document.PICTURE_TYPE_BMP;
+ } else if (imgFile.endsWith(".wpg")) {
+ format = Document.PICTURE_TYPE_WPG;
+ } else {
+ System.err.println("Unsupported picture: " + imgFile +
+ ". Expected emf|wmf|pict|jpeg|png|dib|gif|tiff|eps|bmp|wpg");
+ continue;
+ }
+
+ r.setText(imgFile);
+ r.addBreak();
+ try (FileInputStream is = new FileInputStream(imgFile)) {
+ r.addPicture(is, format, imgFile, Units.toEMU(200), Units.toEMU(200)); // 200x200 pixels
+ }
+ r.addBreak(BreakType.PAGE);
+ }
+
+ try (FileOutputStream out = new FileOutputStream("images.docx")) {
+ doc.write(out);
+ }
+ }
+ }
+
+
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/SimpleTable.java b/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/SimpleTable.java
new file mode 100644
index 0000000000..4b9e51e1d1
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/SimpleTable.java
@@ -0,0 +1,199 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.examples.xwpf.usermodel;
+
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.util.List;
+
+import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
+import org.apache.poi.xwpf.usermodel.UnderlinePatterns;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.apache.poi.xwpf.usermodel.XWPFParagraph;
+import org.apache.poi.xwpf.usermodel.XWPFRun;
+import org.apache.poi.xwpf.usermodel.XWPFTable;
+import org.apache.poi.xwpf.usermodel.XWPFTableCell;
+import org.apache.poi.xwpf.usermodel.XWPFTableRow;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHeight;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTShd;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTString;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblPr;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTrPr;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTVerticalJc;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.STShd;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.STVerticalJc;
+
+/**
+ * This program creates a simple WordprocessingML table using POI XWPF API, and
+ * a more complex, styled table using both XWPF and poi-ooxml-full. It's possible
+ * that not all referenced wordprocessingml classes are defined in the
+ * poi-ooxml-lite jar. If this is the case, you'll need to use the
+ * poi-ooxml-full jar library.
+ *
+ * @author gisella bronzetti (original)
+ * @author Gregg Morris (styled table)
+ */
+public class SimpleTable {
+
+ public static void main(String[] args) throws Exception {
+ try {
+ createSimpleTable();
+ }
+ catch(Exception e) {
+ System.out.println("Error trying to create simple table.");
+ throw(e);
+ }
+ try {
+ createStyledTable();
+ }
+ catch(Exception e) {
+ System.out.println("Error trying to create styled table.");
+ throw(e);
+ }
+ }
+
+ public static void createSimpleTable() throws Exception {
+ try (XWPFDocument doc = new XWPFDocument()) {
+ XWPFTable table = doc.createTable(3, 3);
+
+ table.getRow(1).getCell(1).setText("EXAMPLE OF TABLE");
+
+ // table cells have a list of paragraphs; there is an initial
+ // paragraph created when the cell is created. If you create a
+ // paragraph in the document to put in the cell, it will also
+ // appear in the document following the table, which is probably
+ // not the desired result.
+ XWPFParagraph p1 = table.getRow(0).getCell(0).getParagraphs().get(0);
+
+ XWPFRun r1 = p1.createRun();
+ r1.setBold(true);
+ r1.setText("The quick brown fox");
+ r1.setItalic(true);
+ r1.setFontFamily("Courier");
+ r1.setUnderline(UnderlinePatterns.DOT_DOT_DASH);
+ r1.setTextPosition(100);
+
+ table.getRow(2).getCell(2).setText("only text");
+
+ try (OutputStream out = new FileOutputStream("simpleTable.docx")) {
+ doc.write(out);
+ }
+ }
+ }
+
+ /**
+ * Create a table with some row and column styling. I "manually" add the
+ * style name to the table, but don't check to see if the style actually
+ * exists in the document. Since I'm creating it from scratch, it obviously
+ * won't exist. When opened in MS Word, the table style becomes "Normal".
+ * I manually set alternating row colors. This could be done using Themes,
+ * but that's left as an exercise for the reader. The cells in the last
+ * column of the table have 10pt. "Courier" font.
+ * I make no claims that this is the "right" way to do it, but it worked
+ * for me. Given the scarcity of XWPF examples, I thought this may prove
+ * instructive and give you ideas for your own solutions.
+ */
+ public static void createStyledTable() throws Exception {
+ // Create a new document from scratch
+
+ try (XWPFDocument doc = new XWPFDocument()) {
+ // -- OR --
+ // open an existing empty document with styles already defined
+ //XWPFDocument doc = new XWPFDocument(new FileInputStream("base_document.docx"));
+
+ // Create a new table with 6 rows and 3 columns
+ int nRows = 6;
+ int nCols = 3;
+ XWPFTable table = doc.createTable(nRows, nCols);
+
+ // Set the table style. If the style is not defined, the table style
+ // will become "Normal".
+ CTTblPr tblPr = table.getCTTbl().getTblPr();
+ CTString styleStr = tblPr.addNewTblStyle();
+ styleStr.setVal("StyledTable");
+
+ // Get a list of the rows in the table
+ List<XWPFTableRow> rows = table.getRows();
+ int rowCt = 0;
+ int colCt = 0;
+ for (XWPFTableRow row : rows) {
+ // get table row properties (trPr)
+ CTTrPr trPr = row.getCtRow().addNewTrPr();
+ // set row height; units = twentieth of a point, 360 = 0.25"
+ CTHeight ht = trPr.addNewTrHeight();
+ ht.setVal(BigInteger.valueOf(360));
+
+ // get the cells in this row
+ List<XWPFTableCell> cells = row.getTableCells();
+ // add content to each cell
+ for (XWPFTableCell cell : cells) {
+ // get a table cell properties element (tcPr)
+ CTTcPr tcpr = cell.getCTTc().addNewTcPr();
+ // set vertical alignment to "center"
+ CTVerticalJc va = tcpr.addNewVAlign();
+ va.setVal(STVerticalJc.CENTER);
+
+ // create cell color element
+ CTShd ctshd = tcpr.addNewShd();
+ ctshd.setColor("auto");
+ ctshd.setVal(STShd.CLEAR);
+ if (rowCt == 0) {
+ // header row
+ ctshd.setFill("A7BFDE");
+ } else if (rowCt % 2 == 0) {
+ // even row
+ ctshd.setFill("D3DFEE");
+ } else {
+ // odd row
+ ctshd.setFill("EDF2F8");
+ }
+
+ // get 1st paragraph in cell's paragraph list
+ XWPFParagraph para = cell.getParagraphs().get(0);
+ // create a run to contain the content
+ XWPFRun rh = para.createRun();
+ // style cell as desired
+ if (colCt == nCols - 1) {
+ // last column is 10pt Courier
+ rh.setFontSize(10);
+ rh.setFontFamily("Courier");
+ }
+ if (rowCt == 0) {
+ // header row
+ rh.setText("header row, col " + colCt);
+ rh.setBold(true);
+ para.setAlignment(ParagraphAlignment.CENTER);
+ } else {
+ // other rows
+ rh.setText("row " + rowCt + ", col " + colCt);
+ para.setAlignment(ParagraphAlignment.LEFT);
+ }
+ colCt++;
+ } // for cell
+ colCt = 0;
+ rowCt++;
+ } // for row
+
+ // write the file
+ try (OutputStream out = new FileOutputStream("styledTable.docx")) {
+ doc.write(out);
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/UpdateEmbeddedDoc.java b/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/UpdateEmbeddedDoc.java
new file mode 100644
index 0000000000..faf31b3ded
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/UpdateEmbeddedDoc.java
@@ -0,0 +1,181 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.examples.xwpf.usermodel;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.List;
+
+import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
+import org.apache.poi.openxml4j.opc.PackagePart;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.usermodel.WorkbookFactory;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+
+/**
+ * Tests whether it is possible to successfully update an Excel workbook that is
+ * embedded into a WordprocessingML document. Note that the test has currently
+ * only been conducted with a binary Excel workbook and NOT yet with a
+ * SpreadsheetML workbook embedded into the document.<p>
+ *
+ * This code was successfully tested with the following file from the POI test collection:
+ * http://svn.apache.org/repos/asf/poi/trunk/test-data/document/EmbeddedDocument.docx
+ */
+@SuppressWarnings({"java:S106","java:S4823","java:S1192"})
+public class UpdateEmbeddedDoc {
+
+ private XWPFDocument doc;
+ private File docFile;
+
+ private static final int SHEET_NUM = 0;
+ private static final int ROW_NUM = 0;
+ private static final int CELL_NUM = 0;
+ private static final double NEW_VALUE = 100.98D;
+ private static final String BINARY_EXTENSION = "xls";
+ private static final String OPENXML_EXTENSION = "xlsx";
+
+ /**
+ * Create a new instance of the UpdateEmbeddedDoc class using the following
+ * parameters;
+ *
+ * @param filename An instance of the String class that encapsulates the name
+ * of and path to a WordprocessingML Word document that contains an
+ * embedded binary Excel workbook.
+ * @throws java.io.FileNotFoundException Thrown if the file cannot be found
+ * on the underlying file system.
+ * @throws java.io.IOException Thrown if a problem occurs in the underlying
+ * file system.
+ */
+ public UpdateEmbeddedDoc(String filename) throws FileNotFoundException, IOException {
+ this.docFile = new File(filename);
+ if (!this.docFile.exists()) {
+ throw new FileNotFoundException("The Word document " + filename + " does not exist.");
+ }
+ try (FileInputStream fis = new FileInputStream(this.docFile)) {
+ // Open the Word document file and instantiate the XWPFDocument class.
+ this.doc = new XWPFDocument(fis);
+ }
+ }
+
+ /**
+ * Called to update the embedded Excel workbook. As the format and structure
+ * of the workbook are known in advance, all this code attempts to do is
+ * write a new value into the first cell on the first row of the first
+ * worksheet. Prior to executing this method, that cell will contain the
+ * value 1.
+ *
+ * @throws org.apache.poi.openxml4j.exceptions.OpenXML4JException
+ * Rather
+ * than use the specific classes (HSSF/XSSF) to handle the embedded
+ * workbook this method uses those defined in the SS stream. As
+ * a result, it might be the case that a SpreadsheetML file is
+ * opened for processing, throwing this exception if that file is
+ * invalid.
+ * @throws java.io.IOException Thrown if a problem occurs in the underlying
+ * file system.
+ */
+ public void updateEmbeddedDoc() throws OpenXML4JException, IOException {
+ List<PackagePart> embeddedDocs = this.doc.getAllEmbeddedParts();
+ for (PackagePart pPart : embeddedDocs) {
+ String ext = pPart.getPartName().getExtension();
+ if (BINARY_EXTENSION.equals(ext) || OPENXML_EXTENSION.equals(ext)) {
+ // Get an InputStream from the package part and pass that
+ // to the create method of the WorkbookFactory class. Update
+ // the resulting Workbook and then stream that out again
+ // using an OutputStream obtained from the same PackagePart.
+ try (InputStream is = pPart.getInputStream();
+ Workbook workbook = WorkbookFactory.create(is);
+ OutputStream os = pPart.getOutputStream()) {
+ Sheet sheet = workbook.getSheetAt(SHEET_NUM);
+ Row row = sheet.getRow(ROW_NUM);
+ Cell cell = row.getCell(CELL_NUM);
+ cell.setCellValue(NEW_VALUE);
+ workbook.write(os);
+ }
+ }
+ }
+
+ if (!embeddedDocs.isEmpty()) {
+ // Finally, write the newly modified Word document out to file.
+ try (FileOutputStream fos = new FileOutputStream(this.docFile)) {
+ this.doc.write(fos);
+ }
+ }
+ }
+
+ /**
+ * Called to test whether or not the embedded workbook was correctly
+ * updated. This method simply recovers the first cell from the first row
+ * of the first workbook and tests the value it contains.
+ * <p>
+ * Note that execution will not continue up to the assertion as the
+ * embedded workbook is now corrupted and causes an IllegalArgumentException
+ * with the following message
+ * <p>
+ * <em>java.lang.IllegalArgumentException: Your InputStream was neither an
+ * OLE2 stream, nor an OOXML stream</em>
+ * <p>
+ * to be thrown when the WorkbookFactory.createWorkbook(InputStream) method
+ * is executed.
+ *
+ * @throws org.apache.poi.openxml4j.exceptions.OpenXML4JException
+ * Rather
+ * than use the specific classes (HSSF/XSSF) to handle the embedded
+ * workbook this method uses those defined in the SS stream. As
+ * a result, it might be the case that a SpreadsheetML file is
+ * opened for processing, throwing this exception if that file is
+ * invalid.
+ * @throws java.io.IOException Thrown if a problem occurs in the underlying
+ * file system.
+ */
+ public void checkUpdatedDoc() throws OpenXML4JException, IOException {
+ for (PackagePart pPart : this.doc.getAllEmbeddedParts()) {
+ String ext = pPart.getPartName().getExtension();
+ if (BINARY_EXTENSION.equals(ext) || OPENXML_EXTENSION.equals(ext)) {
+ try (InputStream is = pPart.getInputStream();
+ Workbook workbook = WorkbookFactory.create(is)) {
+ Sheet sheet = workbook.getSheetAt(SHEET_NUM);
+ Row row = sheet.getRow(ROW_NUM);
+ Cell cell = row.getCell(CELL_NUM);
+ if(cell.getNumericCellValue() != NEW_VALUE) {
+ throw new IllegalStateException("Failed to validate document content.");
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Code to test updating of the embedded Excel workbook.
+ */
+ public static void main(String[] args) throws IOException, OpenXML4JException {
+ UpdateEmbeddedDoc ued = new UpdateEmbeddedDoc(args[0]);
+ ued.updateEmbeddedDoc();
+ ued.checkUpdatedDoc();
+ }
+}
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/bar-chart-data.txt b/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/bar-chart-data.txt
new file mode 100644
index 0000000000..22c7b86ab8
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/bar-chart-data.txt
@@ -0,0 +1,12 @@
+10 languages with most speakers as first language
+countries,speakers,language
+58,315,العربية
+4,243,বাংলা
+38,1299,中文
+118,378,English
+4,260,हिन्दी
+2,128,日本語
+15,223,português
+6,119,ਪੰਜਾਬੀ
+18,154,Русский язык
+31,442,español
diff --git a/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/bar-chart-template.docx b/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/bar-chart-template.docx
new file mode 100644
index 0000000000..ddd57ef0a3
--- /dev/null
+++ b/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/bar-chart-template.docx
Binary files differ
diff --git a/poi-examples/src/main/java9/module-info.class b/poi-examples/src/main/java9/module-info.class
new file mode 100644
index 0000000000..99c4f271f9
--- /dev/null
+++ b/poi-examples/src/main/java9/module-info.class
Binary files differ
diff --git a/poi-examples/src/main/java9/module-info.java b/poi-examples/src/main/java9/module-info.java
new file mode 100644
index 0000000000..68b580e3ee
--- /dev/null
+++ b/poi-examples/src/main/java9/module-info.java
@@ -0,0 +1,40 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+module org.apache.poi.examples {
+
+ requires transitive org.apache.poi.ooxml;
+ requires transitive org.apache.poi.scratchpad;
+ requires java.xml;
+
+ exports org.apache.poi.examples.crypt;
+ exports org.apache.poi.examples.hpsf;
+ exports org.apache.poi.examples.hslf;
+ exports org.apache.poi.examples.hsmf;
+ exports org.apache.poi.examples.hssf.eventusermodel;
+ exports org.apache.poi.examples.hssf.usermodel;
+ exports org.apache.poi.examples.hwpf;
+ exports org.apache.poi.examples.ss;
+ exports org.apache.poi.examples.ss.formula;
+ exports org.apache.poi.examples.ss.html;
+ exports org.apache.poi.examples.util;
+ exports org.apache.poi.examples.xslf;
+ exports org.apache.poi.examples.xssf.eventusermodel;
+ exports org.apache.poi.examples.xssf.streaming;
+ exports org.apache.poi.examples.xssf.usermodel;
+ exports org.apache.poi.examples.xwpf.usermodel;
+} \ No newline at end of file
diff --git a/poi-examples/src/main/jsp/HSSFExample.jsp b/poi-examples/src/main/jsp/HSSFExample.jsp
new file mode 100644
index 0000000000..4dd0a4f4e5
--- /dev/null
+++ b/poi-examples/src/main/jsp/HSSFExample.jsp
@@ -0,0 +1,116 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<%@page contentType="text/html"
+import="java.io.*,org.apache.poi.poifs.filesystem.POIFSFileSystem,org.apache.poi
+.hssf.record.*,org.apache.poi.hssf.model.*,org.apache.poi.hssf.usermodel.*,org.a
+pache.poi.hssf.util.*" %>
+<html>
+<head><title>Read Excel file </title>
+</head>
+<body>
+An example of using Jakarta POI's HSSF package to read an excel spreadsheet:
+
+
+<form name="form1" method="get" action="">
+Select an Excel file to read.
+ <input type="file" name="xls_filename" onChange="form1.submit()">
+</form>
+
+<%
+ String filename = request.getParameter("xls_filename");
+ if (filename != null && !filename.isEmpty()) {
+%>
+ <br>You chose the file <%= filename %>.
+ <br><br>It's contents are:
+<%
+ try
+ {
+
+ // create a poi workbook from the excel spreadsheet file
+ POIFSFileSystem fs =
+ new POIFSFileSystem(new FileInputStream(filename));
+ HSSFWorkbook wb = new HSSFWorkbook(fs);
+
+ for (int k = 0; k < wb.getNumberOfSheets(); k++)
+ {
+%>
+ <br><br>Sheet <%= k %> <br>
+<%
+
+ HSSFSheet sheet = wb.getSheetAt(k);
+ int rows = sheet.getPhysicalNumberOfRows();
+
+ for (int r = 0; r < rows; r++)
+ {
+ HSSFRow row = sheet.getRow(r);
+ if (row != null) {
+ int cells = row.getPhysicalNumberOfCells();
+%>
+ <br><b>ROW <%=
+row.getRowNum() %> </b>
+<%
+ for (short c = 0; c < cells; c++)
+ {
+ HSSFCell cell = row.getCell(c);
+ if (cell != null) {
+ String value = null;
+
+ switch (cell.getCellType())
+ {
+
+ case HSSFCell.CELL_TYPE_FORMULA :
+ value = "FORMULA ";
+ break;
+
+ case HSSFCell.CELL_TYPE_NUMERIC :
+ value = "NUMERIC value="
+ + cell.getNumericCellValue
+();
+ break;
+
+ case HSSFCell.CELL_TYPE_STRING :
+ value = "STRING value="
+ + cell.getStringCellValue();
+ break;
+
+ default :
+ }
+%>
+ <%= "CELL col="
+
+ + cell.getColumnIndex()
+ + " VALUE=" + value %>
+<%
+ }
+ }
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+%>
+ Error occurred: <%= e.getMessage() %>
+<%
+ e.printStackTrace();
+ }
+
+ }
+%>
+</body>
+</html>
+
diff --git a/poi-examples/src/main/ruby/Makefile b/poi-examples/src/main/ruby/Makefile
new file mode 100644
index 0000000000..a298da3296
--- /dev/null
+++ b/poi-examples/src/main/ruby/Makefile
@@ -0,0 +1,332 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+
+# Makefile for building Poi4R
+#
+# Supported operating systems: Linux, Mac OS X and Windows.
+# See INSTALL file for requirements.
+#
+# Steps to build
+# 1. Edit the sections below as documented
+# 2. make all
+# 3. make install
+#
+# The install target installs the Poi4R python extension in python's
+# site-packages directory. On Mac OS X, it also installs the gcj runtime
+# libraries into $(PREFIX)/lib.
+#
+# To successfully import the Poi4R extension into Ruby, all required
+# libraries need to be found. If the locations you chose are non-standard,
+# the relevant DYLD_LIBRARY_PATH (Mac OS X), LD_LIBRARY_PATH (Linux), or
+# PATH (Windows) need to be set accordingly.
+#
+
+
+VERSION=0.1.0
+POI_VER=$(shell grep '<property name="version.id"' ../../../build.xml | awk -F'"' '{print $$4}')
+RUBY_VER=1.8
+
+POI4R:=$(shell pwd)
+POI=$(POI4R)/poi-$(POI_VER)
+#DEBUG=1
+
+#
+# You need to uncomment and edit the variables below in the section
+# corresponding to your operating system.
+#
+# PREFIX: where programs are normally installed on your system (Unix).
+# PREFIX_RUBY: where your version of python is installed.
+# GCJ_HOME: where GCC/GCJ is installed.
+# Windows drive-absolute paths need to be expressed cygwin style.
+#
+
+# Mac OS X (Darwin)
+#PREFIX=/usr/local
+#PREFIX_RUBY=/Library/Frameworks/Ruby.framework/Versions/$(RUBY_VER)
+#SWIG=$(PREFIX)/bin/swig
+#GCJ_HOME=/usr/local/gcc-3.4.1
+#DB=$(POI4R)/db-$(DB_VER)
+#PREFIX_DB=/usr/local/BerkeleyDB.$(DB_LIB_VER)
+
+# Linux
+PREFIX=/usr
+PREFIX_RUBY=$(PREFIX)
+SWIG=$(PREFIX)/bin/swig
+GCJ_HOME=/usr
+#DB=$(POI4R)/db-$(DB_VER)
+#PREFIX_DB=$(PREFIX)/BerkeleyDB.$(DB_LIB_VER)
+
+# Windows
+#PREFIX_RUBY=/cygdrive/o/Python-2.3.2
+#SWIG=/cygdrive/c/utils/bin/swig.exe
+#GCJ_HOME=/cygdrive/o/mingw-3.1
+#DB=/cygdrive/o/db-$(DB_VER)
+#PREFIX_DB=$(DB)
+
+#
+# No edits required below
+#
+
+OS=$(shell uname)
+ifeq ($(findstring CYGWIN,$(OS)),CYGWIN)
+OS=Cygwin
+endif
+ifeq ($(findstring WINNT,$(OS)),WINNT)
+OS=Cygwin
+endif
+
+ifeq ($(DEBUG),1)
+COMP_OPT=DEBUG=1
+SUFFIX=d
+_SUFFIX=_d
+BINDIR=debug
+else
+COMP_OPT=
+SUFFIX=
+_SUFFIX=
+BINDIR=release
+endif
+
+SWIG_OPT=-DSWIG_COBJECT_TYPES -DPOI4R_VER="'$(VERSION)'" -DPOI_VER="'$(POI_VER)'"
+
+JCCFLAGS=--encoding=UTF-8
+#JCCFLAGS=--encoding=UTF-8 -findirect-dispatch
+
+ifeq ($(OS),Darwin)
+RUBY_SITE=$(PREFIX_RUBY)/lib/ruby$(RUBY_VER)/site-packages
+RUBY_INC=$(PREFIX_RUBY)/lib/ruby$(RUBY_VER)
+POI4R=$(BINDIR)/poi4r.so
+ifeq ($(DEBUG),1)
+CCFLAGS=-O0 -g
+LDFLAGS=-g
+else
+CCFLAGS=-O2
+LDFLAGS=
+endif
+else
+
+ifeq ($(OS),Linux)
+RUBY_SITE=$(PREFIX_RUBY)/lib/ruby/site-ruby/$(RUBY_VER)/
+RUBY_INC=$(PREFIX_RUBY)/lib/ruby/$(RUBY_VER)/i686-linux
+POI4R_LIB=$(BINDIR)/poi4r.so
+ifeq ($(DEBUG),1)
+CCFLAGS=-O0 -g -fPIC
+LDFLAGS=-g
+else
+CCFLAGS=-O2 -fPIC
+LDFLAGS=
+endif
+else
+
+ifeq ($(OS),Cygwin)
+RUBY_SITE=`cygpath -aw $(PREFIX_RUBY)/Lib/site-packages`
+RUBY_INC=`cygpath -aw $(PREFIX_RUBY)/Include`
+RUBY_PC=`cygpath -aw $(PREFIX_RUBY)/PC`
+POI4R_LIB=$(BINDIR)/poi4r$(_SUFFIX).so
+ifeq ($(DEBUG),1)
+CCFLAGS=-O -g
+LDFLAGS=-g
+else
+CCFLAGS=-O2
+LDFLAGS=
+endif
+else
+
+RUBY=unknown
+RUBY_SITE=unknown
+endif
+endif
+endif
+
+CLASSES=$(BINDIR)/classes
+JAR_CLASSES=$(CLASSES)/jar
+
+CC=$(GCJ_HOME)/bin/gcc
+CXX=$(GCJ_HOME)/bin/g++
+JCC=$(GCJ_HOME)/bin/gcj
+JCCH=$(GCJ_HOME)/bin/gcjh
+JAR=$(GCJ_HOME)/bin/jar
+POI_ZIP=poi-$(POI_VER).jar
+POI_JAR=poi-$(POI_VER).jar
+POI_JAR_WC=poi-$(POI_VER)-*.jar
+
+POI4R_CP:=$(BINDIR)/$(POI_JAR):$(CLASSES)
+
+OBJS=$(BINDIR)/poi.o $(BINDIR)/io.java.o $(BINDIR)/io.cpp.o
+
+LIBS=$(POI4R_LIB)
+
+default: all
+
+patches:
+
+
+env:
+ifndef PREFIX_RUBY
+ @echo Operating system is $(OS)
+ @echo You need to edit that section of the Makefile
+ @false
+else
+ @true
+endif
+
+
+$(BINDIR):
+ mkdir -p $(BINDIR)/classes/jar
+
+
+DISTRIB=Poi-$(VERSION)
+
+ifeq ($(OS),Cygwin)
+POI4R_CP:=`cygpath -awp $(POI4R_CP)`
+endif
+
+
+ifeq ($(OS),Cygwin)
+_poi=`cygpath -aw $(POI)`
+else
+_poi=$(POI)
+endif
+
+$(BINDIR)/$(POI_JAR):
+ cp ../../../build/dist/$(POI_JAR_WC) $(BINDIR)/$(POI_JAR)
+ cd $(JAR_CLASSES); $(JAR) -xf ../../$(POI_JAR)
+
+$(BINDIR)/io.java.o: java/org/apache/poi/RubyOutputStream.java
+ $(JCC) $(JCCFLAGS) -C -d $(CLASSES) java/org/apache/poi/RubyOutputStream.java
+ $(JCC) $(JCCFLAGS) $(CCFLAGS) -I$(GCJ_HOME)/include -c -o $@ java/org/apache/poi/RubyOutputStream.java
+
+$(CLASSES)/org/apache/poi/RubyOutputStream.h: $(BINDIR)/io.java.o Makefile
+ mkdir -p $(CLASSES)/org/apache/poi/hssf/usermodel
+ $(JCCH) -d $(CLASSES) --classpath=$(JAR_CLASSES) org.apache.poi.hssf.usermodel.HSSFWorkbook
+ $(JCCH) -d $(CLASSES) --classpath=$(JAR_CLASSES) org.apache.poi.hssf.usermodel.HSSFSheet
+ $(JCCH) -d $(CLASSES) --classpath=$(JAR_CLASSES) org.apache.poi.hssf.usermodel.HSSFRow
+ $(JCCH) -d $(CLASSES) --classpath=$(JAR_CLASSES) org.apache.poi.hssf.usermodel.HSSFCell
+ $(JCCH) -d $(CLASSES) --classpath=$(JAR_CLASSES) org.apache.poi.hssf.usermodel.HSSFHeader
+ $(JCCH) -d $(CLASSES) --classpath=$(JAR_CLASSES) org.apache.poi.hssf.usermodel.HSSFFooter
+ $(JCCH) -d $(CLASSES) --classpath=$(JAR_CLASSES) org.apache.poi.hssf.usermodel.HSSFFont
+ $(JCCH) -d $(CLASSES) --classpath=$(JAR_CLASSES) org.apache.poi.hssf.usermodel.HSSFDataFormat
+ $(JCCH) -d $(CLASSES) --classpath=$(JAR_CLASSES) org.apache.poi.hssf.usermodel.HSSFCellStyle
+ $(JCCH) -d $(CLASSES) --classpath=$(CLASSES) org.apache.poi.RubyOutputStream
+
+
+$(BINDIR)/io.cpp.o: $(CLASSES)/org/apache/poi/RubyOutputStream.h cpp/RubyIO.cpp $(BINDIR)/io.java.o
+ $(JCC) -I$(RUBY_INC) -I$(GCJ_HOME)/include -I$(CLASSES) $(CCFLAGS) -c -o $@ cpp/RubyIO.cpp
+
+$(BINDIR)/poi.o: $(BINDIR)/$(POI_JAR)
+ $(JCC) $(JCCFLAGS) $(CCFLAGS) -c -o $@ $(BINDIR)/$(POI_JAR)
+
+Poi4R_wrap.cxx: $(BINDIR)/io.cpp.o Poi4R.i
+ifdef SWIG
+ $(SWIG) $(SWIG_OPT) -I$(CLASSES) -c++ -ruby Poi4R.i
+endif
+
+
+ifeq ($(OS),Darwin)
+$(POI4R_LIB): $(OBJS) Poi4R_wrap.cxx
+ $(CXX) -shared -bundle -o $@ $(CCFLAGS) $(SWIG_OPT) $(DB_INC) -I$(GCJ_HOME)/include -I$(CLASSES) -I$(RUBY_INC) Poi4R_wrap.cxx $(OBJS) -L$(GCJ_HOME)/lib -lgcj -liconv -undefined suppress -flat_namespace -multiply_defined suppress
+else
+
+ifeq ($(OS),Linux)
+$(POI4R_LIB): $(OBJS) Poi4R_wrap.cxx
+ $(CXX) -shared -o $@ $(CCFLAGS) $(SWIG_OPT) $(DB_INC) -I$(CLASSES) -I$(RUBY_INC) Poi4R_wrap.cxx $(OBJS) -lgcj
+else
+
+ifeq ($(OS),Cygwin)
+$(POI4R_LIB): $(OBJS) Poi4R_wrap.cxx
+ $(CXX) -c $(CCFLAGS) $(PYDBG) -D_NO_OLDNAMES -D_off_t=off_t $(SWIG_OPT) $(DB_INC) -I$(CLASSES) -I$(RUBY_PC) -I$(RUBY_INC) -o $(BINDIR)/Poi4R_wrap.o Poi4R_wrap.cxx
+ $(CXX) -shared $(LDFLAGS) -o $@ $(OBJS) `cygpath -aw $(PREFIX_RUBY)/python23$(_SUFFIX).dll` $(BINDIR)/Poi4R_wrap.o -lgcj -lwin32k -lws2_32
+endif
+endif
+endif
+
+
+all: env $(BINDIR) $(LIBS)
+ @echo build of $(POI4R_LIB) complete
+
+install:: all
+ install Poi4R.rb $(RUBY_SITE)
+ install $(POI4R_LIB) $(RUBY_SITE)
+
+ifeq ($(OS),Darwin)
+install::
+ install $(GCJ_HOME)/lib/libgcj.5.dylib $(PREFIX)/lib
+ install $(GCJ_HOME)/lib/libstdc++.6.dylib $(PREFIX)/lib
+ install $(GCJ_HOME)/lib/libgcc_s.1.0.dylib $(PREFIX)/lib
+else
+
+ifeq ($(OS),Linux)
+install::
+
+else
+
+ifeq ($(OS),Cygwin)
+install::
+
+endif
+endif
+endif
+
+
+clean:
+ rm -rf $(BINDIR) Poi4R.rb* Poi4R_wrap.cxx
+
+realclean: clean
+ rm -rf $(POI) $(STORE) $(DISTRIB)
+
+distrib::
+ mkdir -p $(DISTRIB)/python
+ install Poi4R.rb $(DISTRIB)/python
+ install $(POI4R_LIB) $(DISTRIB)/python
+ install README $(DISTRIB)
+
+ifeq ($(OS),Darwin)
+distrib::
+ifdef DB
+ mkdir -p $(DISTRIB)/db
+ install $(LIBDB_JAVA_LIB) $(DISTRIB)/db
+ install libdb_java-$(DB_LIB_VER).la.osx $(DISTRIB)/db
+endif
+ mkdir -p $(DISTRIB)/gcj
+ install $(GCJ_HOME)/lib/libgcj.5.dylib $(DISTRIB)/gcj
+ install $(GCJ_HOME)/lib/libstdc++.6.dylib $(DISTRIB)/gcj
+ install $(GCJ_HOME)/lib/libgcc_s.1.0.dylib $(DISTRIB)/gcj
+else
+
+ifeq ($(OS),Linux)
+distrib::
+ifdef DB
+ mkdir -p $(DISTRIB)/db
+ install $(LIBDB_JAVA_LIB) $(DISTRIB)/db
+endif
+ mkdir -p $(DISTRIB)/gcj
+ install $(GCJ_HOME)/lib/libgcj.so.5 $(DISTRIB)/gcj
+ install $(GCJ_HOME)/lib/libstdc++.so.6 $(DISTRIB)/gcj
+ install $(GCJ_HOME)/lib/libgcc_s.so.1 $(DISTRIB)/gcj
+else
+
+ifeq ($(OS),Cygwin)
+distrib::
+ifdef DB
+ mkdir -p $(DISTRIB)/db
+ install $(LIBDB_JAVA_LIB) $(DISTRIB)/db
+endif
+endif
+endif
+endif
+
diff --git a/poi-examples/src/main/ruby/Poi4R.i b/poi-examples/src/main/ruby/Poi4R.i
new file mode 100644
index 0000000000..2f72ce9948
--- /dev/null
+++ b/poi-examples/src/main/ruby/Poi4R.i
@@ -0,0 +1,614 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+%module poi4r
+
+
+%{
+
+#include <gcj/cni.h>
+#include <java/lang/Object.h>
+#include <java/lang/Thread.h>
+#include <java/lang/ThreadGroup.h>
+#include <java/lang/Runnable.h>
+#include <java/lang/String.h>
+#include <java/lang/Throwable.h>
+#include <java/lang/Comparable.h>
+#include <java/lang/Integer.h>
+#include <java/lang/Long.h>
+#include <java/lang/Float.h>
+#include <java/lang/Double.h>
+#include <java/io/StringWriter.h>
+#include <java/io/PrintWriter.h>
+#include <java/util/HashMap.h>
+#include <java/util/Date.h>
+#include <java/util/Calendar.h>
+#include <java/lang/System.h>
+
+#include "org/apache/poi/hssf/usermodel/HSSFWorkbook.h"
+#include "org/apache/poi/hssf/usermodel/HSSFSheet.h"
+#include "org/apache/poi/hssf/usermodel/HSSFRow.h"
+#include "org/apache/poi/hssf/usermodel/HSSFCell.h"
+#include "org/apache/poi/hssf/usermodel/HSSFFont.h"
+#include "org/apache/poi/hssf/usermodel/HSSFCellStyle.h"
+#include "org/apache/poi/hssf/usermodel/HSSFDataFormat.h"
+#include "org/apache/poi/hssf/usermodel/HSSFHeader.h"
+#include "org/apache/poi/hssf/usermodel/HSSFFooter.h"
+#include "org/apache/poi/RubyOutputStream.h"
+
+
+typedef ::org::apache::poi::hssf::usermodel::HSSFWorkbook *jhworkbook;
+typedef ::org::apache::poi::hssf::usermodel::HSSFSheet *jhsheet;
+typedef ::org::apache::poi::hssf::usermodel::HSSFRow *jhrow;
+typedef ::org::apache::poi::hssf::usermodel::HSSFCell *jhcell;
+typedef ::org::apache::poi::hssf::usermodel::HSSFCellStyle *jhcellstyle;
+typedef ::org::apache::poi::hssf::usermodel::HSSFFont *jhfont;
+typedef ::org::apache::poi::hssf::usermodel::HSSFFooter *jhfooter;
+typedef ::org::apache::poi::hssf::usermodel::HSSFHeader *jhheader;
+typedef ::org::apache::poi::hssf::usermodel::HSSFDataFormat *jhdataformat;
+
+typedef ::java::util::Date *jdate;
+typedef ::java::util::Calendar *jcalendar;
+typedef ::java::io::OutputStream *joutputstream;
+typedef ::java::io::InputStream *jinputstream;
+typedef ::java::util::Collection *jstringCollection;
+typedef ::java::util::Collection *jtermCollection;
+typedef ::java::util::Locale *jlocale;
+typedef ::java::lang::Comparable *jcomparable;
+typedef JArray<jobject> *jobjectArray;
+typedef JArray<jstring> *jstringArray;
+
+
+static java::lang::Thread *nextThread;
+static java::util::HashMap *objects;
+
+
+static void store_reference(jobject object) {
+ java::lang::Integer *ji =new java::lang::Integer(java::lang::System::identityHashCode(object));
+ jobject jo = objects->get(ji);
+ if (!jo) {
+ // printf("put object in hash\n");
+ objects->put(ji,object);
+ }
+}
+static VALUE jo2rv(jobject object, swig_type_info *descriptor)
+{
+ if (object == NULL)
+ {
+ return Qnil;
+ }
+ else
+ {
+ return SWIG_NewPointerObj((void *) object, descriptor, 0);
+ }
+}
+static int cvtptr(VALUE value, void **jo, swig_type_info *info)
+{
+ if (SWIG_ConvertPtr(value, jo, info, 0) == 0)
+ return 0;
+ else
+ {
+ return -1;
+ }
+}
+
+static int rv2jo(VALUE rv, jobject *jo, swig_type_info *descriptor)
+{
+ if (NIL_P(rv))
+ *jo = NULL;
+ else
+ {
+ java::lang::Object *javaObj;
+
+ if (cvtptr(rv, (void **) &javaObj, descriptor) == -1)
+ return 0;
+
+ *jo = javaObj;
+ }
+
+ return 1;
+}
+
+
+static jstring r2j(VALUE object)
+{
+ if (NIL_P(object)){
+ return NULL;
+ }
+ else {
+ char *ps = STR2CSTR(object);
+ jstring js = JvNewStringLatin1(ps);
+
+ if (!js)
+ {
+ rb_raise(rb_eRuntimeError, "ruby str cannot be converted to java: %s",ps);
+ }
+
+ return js;
+ }
+}
+
+VALUE j2r(jstring js)
+{
+ if (!js)
+ {
+ return Qnil;
+ }
+ else
+ {
+ jint len = JvGetStringUTFLength(js);
+ char buf[len + 1];
+
+ JvGetStringUTFRegion(js, 0, len, buf);
+ buf[len] = '\0';
+
+ return rb_str_new2(buf);
+ }
+}
+
+static void free_java_obj(void* arg1) {
+ jobject object =(jobject) arg1;
+ java::lang::Integer *ji =new java::lang::Integer(java::lang::System::identityHashCode(object));
+ jobject jo = objects->get(ji);
+ if (jo) {
+ // printf("removed object from hash\n");
+ objects->remove(ji);
+ }
+}
+
+static void raise_ruby_error(java::lang::Throwable *e) {
+ java::io::StringWriter *buffer = new java::io::StringWriter();
+ java::io::PrintWriter *writer = new java::io::PrintWriter(buffer);
+ e->printStackTrace(writer);
+ writer->close();
+ jstring message = buffer->toString();
+ jint len = JvGetStringUTFLength(message);
+ char buf[len + 1];
+ JvGetStringUTFRegion(message, 0, len, buf);
+ buf[len] = '\0';
+ rb_raise(rb_eRuntimeError, "error calling poi \n %s", buf);
+}
+
+%}
+
+typedef long jint;
+typedef long long jlong;
+typedef char jbyte;
+typedef float jfloat;
+typedef float jdouble;
+typedef int jshort;
+typedef bool jboolean;
+
+%typemap(in) SWIGTYPE * {
+
+ if (!rv2jo($input, (jobject *) &$1, $1_descriptor))
+ rb_raise(rb_eRuntimeError, "Unrecoverable error in SWIG typemapping");
+}
+%typemap(out) SWIGTYPE * {
+
+ $result = jo2rv($1, $1_descriptor);
+}
+
+%typemap(in) org::apache::poi::hssf::usermodel::HSSFWorkbook{
+
+ if (!rv2jo($input, (jobject *) &$1,
+ $descriptor(org::apache::poi::hssf::usermodel::HSSFWorkbook *)))
+ SWIG_fail;
+}
+%typemap(out) org::apache::poi::hssf::usermodel::HSSFWorkbook {
+ $result = jo2rv($1, $descriptor(org::apache::poi::hssf::usermodel::HSSFWorkbook *));
+}
+
+%typemap(in) jhsheet{
+
+ if (!rv2jo($input, (jobject *) &$1,
+ $descriptor(org::apache::poi::hssf::usermodel::HSSFSheet *)))
+ SWIG_fail;
+}
+%typemap(out) jhsheet {
+
+ $result = jo2rv($1, $descriptor(org::apache::poi::hssf::usermodel::HSSFSheet *));
+}
+%typemap(in) jhrow{
+
+ if (!rv2jo($input, (jobject *) &$1,
+ $descriptor(org::apache::poi::hssf::usermodel::HSSFRow *)))
+ SWIG_fail;
+}
+%typemap(out) jhrow {
+
+ $result = jo2rv($1, $descriptor(org::apache::poi::hssf::usermodel::HSSFRow *));
+}
+%typemap(in) jhcell{
+
+ if (!rv2jo($input, (jobject *) &$1,
+ $descriptor(org::apache::poi::hssf::usermodel::HSSFCell *)))
+ SWIG_fail;
+}
+%typemap(out) jhcell {
+
+ $result = jo2rv($1, $descriptor(org::apache::poi::hssf::usermodel::HSSFCell *));
+}
+%typemap(in) jhfont{
+
+ if (!rv2jo($input, (jobject *) &$1,
+ $descriptor(org::apache::poi::hssf::usermodel::HSSFFont *)))
+ rb_raise(rb_eRuntimeError, "Unrecoverable error in SWIG typemapping of HSSFFont");
+}
+
+%typemap(out) jhfont {
+
+ $result = jo2rv($1, $descriptor(org::apache::poi::hssf::usermodel::HSSFFont *));
+}
+
+%typemap(in) jhcellstyle{
+
+ if (!rv2jo($input, (jobject *) &$1,
+ $descriptor(org::apache::poi::hssf::usermodel::HSSFCellStyle *)))
+ rb_raise(rb_eRuntimeError, "Unrecoverable error in SWIG typemapping of HSSFCellStyle");
+}
+%typemap(out) jhcellstyle {
+
+ $result = jo2rv($1, $descriptor(org::apache::poi::hssf::usermodel::HSSFCellStyle *));
+}
+%typemap(in) jhdataformat{
+
+ if (!rv2jo($input, (jobject *) &$1,
+ $descriptor(org::apache::poi::hssf::usermodel::HSSFDataFormat *)))
+ rb_raise(rb_eRuntimeError, "Unrecoverable error in SWIG typemapping of HSSFDataFormat");
+}
+%typemap(out) jhdataformat {
+
+ $result = jo2rv($1, $descriptor(org::apache::poi::hssf::usermodel::HSSFDataFormat *));
+}
+
+
+%typemap(in) jstring {
+ $1 = r2j($input);
+}
+%typemap(out) jstring {
+ $result = j2r($1);
+}
+%typecheck(SWIG_TYPECHECK_STRING) jstring {
+ $1 = ( NIL_P($input) || TYPE($input)==T_STRING );
+}
+
+%typemap(in) joutputstream {
+
+ jlong ptr;
+ if (!rb_respond_to($input, rb_intern("putc"))) rb_raise(rb_eTypeError,"Expected IO");
+ *(VALUE *) &ptr = (VALUE) $input;
+ $1 = new org::apache::poi::RubyOutputStream(ptr);
+}
+%typemap(in) jcalendar {
+ $1 = java::util::Calendar::getInstance();
+ //$1->setTimeInMillis((long long) NUM2DBL(rb_funcall($input,rb_intern("to_i"),0,NULL))*1000.0);
+ $1->set(FIX2INT(rb_funcall($input,rb_intern("year"),0,NULL)),
+ FIX2INT(rb_funcall($input,rb_intern("mon"),0,NULL))-1,
+ FIX2INT(rb_funcall($input,rb_intern("day"),0,NULL)),
+ FIX2INT(rb_funcall($input,rb_intern("hour"),0,NULL)),
+ FIX2INT(rb_funcall($input,rb_intern("min"),0,NULL)),
+ FIX2INT(rb_funcall($input,rb_intern("sec"),0,NULL))
+ );
+}
+
+%typecheck(SWIG_TYPECHECK_POINTER) jcalendar {
+ $1 = rb_respond_to($input, rb_intern("asctime"));
+}
+
+%typemap(out) jdate {
+ jlong t = ((jdate) $1)->getTime();
+ //TODO: separate seconds and microsecs
+ int ts=t/1000;
+ $result=rb_time_new((time_t) ts, 0 );
+}
+
+
+%freefunc org::apache::poi::hssf::usermodel::HSSFWorkbook "free_java_obj";
+
+%exception {
+ try {
+ $action
+ } catch (java::lang::Throwable *e) {
+ raise_ruby_error(e);
+ }
+}
+%exception org::apache::poi::hssf::usermodel::HSSFWorkbook::HSSFWorkbook {
+ try {
+ $action
+ store_reference(result);
+ } catch (java::lang::Throwable *e) {
+ raise_ruby_error(e);
+ }
+}
+
+
+
+
+namespace java {
+ namespace lang {
+ class Object {
+ jstring toString();
+ };
+%nodefault;
+ class System : public Object {
+ public:
+ static jstring getProperty(jstring);
+ static jstring getProperty(jstring, jstring);
+ static void load(jstring);
+ static void loadLibrary(jstring);
+ static void mapLibraryName(jstring);
+ static void runFinalization();
+ static void setProperty(jstring, jstring);
+ };
+%makedefault;
+ }
+ namespace io {
+%nodefault;
+ class InputStream : public ::java::lang::Object {
+ };
+ class OutputStream : public ::java::lang::Object {
+ };
+
+%makedefault;
+ }
+ namespace util {
+ class Date : public ::java::lang::Object {
+ public:
+ Date();
+ Date(jlong);
+ void setTime(jlong);
+ jstring toString();
+ };
+ }
+}
+
+
+namespace org {
+ namespace apache {
+ namespace poi {
+ namespace hssf {
+ namespace usermodel {
+%nodefault;
+ class HSSFWorkbook : public ::java::lang::Object {
+ public:
+ HSSFWorkbook();
+ jstring getSheetName(jint);
+ jint getNumberOfSheets();
+ void setSheetOrder(jstring,jint);
+ void setSheetName(jint,jstring);
+ void setSheetName(jint,jstring,jshort);
+ jint getSheetIndex(jstring);
+ jhsheet createSheet();
+ jhsheet cloneSheet(jint);
+ jhsheet createSheet(jstring);
+ jhsheet getSheetAt(jint);
+ jhsheet getSheet(jstring);
+ void removeSheetAt(jint);
+ jhcellstyle createCellStyle();
+ jhfont createFont();
+ jhdataformat createDataFormat();
+ void write(joutputstream);
+
+ };
+
+ class HSSFSheet : public ::java::lang::Object {
+ public:
+ jhrow createRow(jint);
+ jhrow getRow(jint);
+ jhfooter getFooter();
+ jhheader getHeader();
+ };
+ class HSSFRow : public ::java::lang::Object {
+ public:
+ jhcell createCell(jshort);
+ jhcell getCell(jshort);
+ //jboolean getProtect(); //only in 2.5
+
+ };
+ class HSSFCell : public ::java::lang::Object {
+ public:
+ void setCellValue(jdouble);
+ void setCellValue(jstring);
+ void setCellValue(jboolean);
+ void setCellValue(jcalendar);
+ void setCellFormula(jstring);
+ jstring getStringCellValue();
+ jdouble getNumericCellValue();
+ jdate getDateCellValue();
+ jstring getCellFormula();
+ jboolean getBooleanCellValue();
+ jint getCellType();
+ jshort getEncoding();
+ void setAsActiveCell();
+
+ void setCellStyle(jhcellstyle);
+ void setEncoding(jshort encoding);
+
+ static const jint CELL_TYPE_BLANK;
+ static const jint CELL_TYPE_BOOLEAN;
+ static const jint CELL_TYPE_ERROR;
+ static const jint CELL_TYPE_FORMULA;
+ static const jint CELL_TYPE_NUMERIC;
+ static const jint CELL_TYPE_STRING;
+
+ static const jshort ENCODING_COMPRESSED_UNICODE;
+ static const jshort ENCODING_UTF_16;
+ };
+ class HSSFCellStyle : public ::java::lang::Object {
+ public:
+ static const jshort ALIGN_CENTER;
+ static const jshort ALIGN_CENTER_SELECTION;
+ static const jshort ALIGN_FILL;
+ static const jshort ALIGN_GENERAL;
+ static const jshort ALIGN_JUSTIFY;
+ static const jshort ALIGN_LEFT;
+ static const jshort ALIGN_RIGHT;
+ static const jshort ALT_BARS;
+ static const jshort BIG_SPOTS;
+ static const jshort BORDER_DASH_DOT;
+ static const jshort BORDER_DASH_DOT_DOT;
+ static const jshort BORDER_DASHED;
+ static const jshort BORDER_DOTTED;
+ static const jshort BORDER_DOUBLE;
+ static const jshort BORDER_HAIR;
+ static const jshort BORDER_MEDIUM;
+ static const jshort BORDER_MEDIUM_DASH_DOT;
+ static const jshort BORDER_MEDIUM_DASH_DOT_DOT;
+ static const jshort BORDER_MEDIUM_DASHED;
+ static const jshort BORDER_NONE;
+ static const jshort BORDER_SLANTED_DASH_DOT;
+ static const jshort BORDER_THICK;
+ static const jshort BORDER_THIN;
+ static const jshort BRICKS;
+ static const jshort DIAMONDS;
+ static const jshort FINE_DOTS;
+ static const jshort NO_FILL;
+ static const jshort SOLID_FOREGROUND;
+ static const jshort SPARSE_DOTS;
+ static const jshort SQUARES;
+ static const jshort THICK_BACKWARD_DIAG;
+ static const jshort THICK_FORWARD_DIAG;
+ static const jshort THICK_HORZ_BANDS;
+ static const jshort THICK_VERT_BANDS;
+ static const jshort THIN_BACKWARD_DIAG;
+ static const jshort THIN_FORWARD_DIAG;
+ static const jshort THIN_HORZ_BANDS;
+ static const jshort THIN_VERT_BANDS;
+ static const jshort VERTICAL_BOTTOM;
+ static const jshort VERTICAL_CENTER;
+ static const jshort VERTICAL_JUSTIFY;
+ static const jshort VERTICAL_TOP;
+
+ jshort getAlignment();
+ jshort getBorderBottom();
+ jshort getBorderLeft();
+ jshort getBorderRight();
+ jshort getBorderTop();
+ jshort getBottomBorderColor();
+ jshort getDataFormat();
+ jshort getFillBackgroundColor();
+ jshort getFillForegroundColor();
+ jshort getFillPattern();
+ jshort getFontIndex();
+ jboolean getHidden();
+ jshort getIndention();
+ jshort getIndex();
+ jshort getLeftBorderColor();
+ jboolean getLocked();
+ jshort getRightBorderColor();
+ jshort getRotation();
+ jshort getTopBorderColor();
+ jshort getVerticalAlignment();
+ jboolean getWrapText();
+ void setAlignment(jshort) ;
+ void setBorderBottom(jshort );
+ void setBorderLeft(jshort );
+ void setBorderRight(jshort );
+ void setBorderTop(jshort );
+ void setBottomBorderColor(jshort );
+ void setDataFormat(jshort );
+ void setFillBackgroundColor(jshort );
+ void setFillForegroundColor(jshort );
+ void setFillPattern(jshort );
+ void setFont(jhfont );
+ void setHidden(jboolean );
+ void setIndention(jshort );
+ void setLeftBorderColor(jshort );
+ void setLocked(jboolean );
+ void setRightBorderColor(jshort );
+ void setRotation(jshort );
+ void setTopBorderColor(jshort );
+ void setVerticalAlignment(jshort );
+ void setWrapText(jboolean );
+ };
+ class HSSFDataFormat : public ::java::lang::Object {
+ public:
+ static jstring getBuiltinFormat(jshort);
+ static jshort getBuiltinFormat(jstring);
+ jstring getFormat(jshort);
+ jshort getFormat(jstring);
+ static jint getNumberOfBuiltinBuiltinFormats();
+ //TODO static jlist getBuiltinFormats();
+
+ };
+ class HSSFFont : public ::java::lang::Object {
+ public:
+ static const jshort BOLDWEIGHT_BOLD;
+static const jshort BOLDWEIGHT_NORMAL;
+static const jshort COLOR_NORMAL;
+static const jshort COLOR_RED;
+static const jstring FONT_ARIAL;
+static const jshort SS_NONE;
+static const jshort SS_SUB;
+static const jshort SS_SUPER;
+static const jshort U_DOUBLE;
+static const jshort U_DOUBLE_ACCOUNTING;
+static const jshort U_NONE;
+static const jshort U_SINGLE;
+static const jshort U_SINGLE_ACCOUNTING;
+
+ jshort getBoldweight();
+ jshort getColor();
+ jshort getFontHeight();
+ jshort getFontHeightInPoints();
+ jstring getFontName();
+ jshort getIndex();
+ jboolean getItalic();
+ jboolean getStrikeout();
+ jshort getTypeOffset();
+ jshort getUnderline();
+ void setBoldweight(jshort );
+ void setColor(jshort );
+ void setFontHeight(jshort );
+ void setFontHeightInPoints(jshort );
+ void setFontName(jstring );
+ void setItalic(jboolean );
+ void setStrikeout(jboolean );
+ void setTypeOffset(jshort );
+ void setUnderline(jshort );
+};
+%makedefault;
+ }
+ }
+ }
+ }
+}
+
+
+
+
+
+%init %{
+
+ JvCreateJavaVM(NULL);
+ JvAttachCurrentThread(NULL, NULL);
+
+ nextThread = new java::lang::Thread();
+ objects = new java::util::HashMap();
+
+ java::util::HashMap *props = (java::util::HashMap *)
+ java::lang::System::getProperties();
+ props->put(JvNewStringUTF("inRuby"), objects);
+
+ JvInitClass(&org::apache::poi::hssf::usermodel::HSSFFont::class$);
+ JvInitClass(&org::apache::poi::hssf::usermodel::HSSFCell::class$);
+ JvInitClass(&org::apache::poi::hssf::usermodel::HSSFSheet::class$);
+ JvInitClass(&org::apache::poi::hssf::usermodel::HSSFCellStyle::class$);
+
+%}
+
diff --git a/poi-examples/src/main/ruby/cpp/RubyIO.cpp b/poi-examples/src/main/ruby/cpp/RubyIO.cpp
new file mode 100644
index 0000000000..d4a4638cf0
--- /dev/null
+++ b/poi-examples/src/main/ruby/cpp/RubyIO.cpp
@@ -0,0 +1,44 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+#include <gcj/cni.h>
+
+#include "ruby.h"
+#include "org/apache/poi/RubyOutputStream.h"
+
+
+/**
+ * The native functions declared in org.apache.poi.RubyoutputStream
+ *
+ * @author aviks
+ */
+
+ namespace org {
+ namespace apache {
+ namespace poi {
+
+ void RubyOutputStream::close(void)
+ {
+ rb_funcall3((VALUE ) rubyIO, rb_intern("close"), 0, NULL);
+ }
+
+ void RubyOutputStream::write(jint toWrite)
+ {
+ rb_funcall((VALUE ) rubyIO, rb_intern("putc"),1,INT2FIX(toWrite));
+ }
+ }
+ }
+}
diff --git a/poi-examples/src/main/ruby/java/org/apache/poi/RubyOutputStream.java b/poi-examples/src/main/ruby/java/org/apache/poi/RubyOutputStream.java
new file mode 100644
index 0000000000..e23a0a7d39
--- /dev/null
+++ b/poi-examples/src/main/ruby/java/org/apache/poi/RubyOutputStream.java
@@ -0,0 +1,62 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+
+package org.apache.poi;
+
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * @author aviks
+ * Wrap a java.io.OutputStream around a Ruby IO object
+ */
+
+public class RubyOutputStream extends OutputStream {
+
+ //pointer to native ruby VALUE
+ protected long rubyIO;
+
+ public RubyOutputStream (long rubyIO)
+ {
+ this.rubyIO = rubyIO;
+// incRef();
+ }
+
+ @Override
+ protected void finalize()
+ throws Throwable
+ {
+// decRef();
+ }
+
+// protected native void incRef();
+// protected native void decRef();
+
+ @Override
+ public native void close()
+ throws IOException;
+
+
+ /* (non-Javadoc)
+ * @see java.io.OutputStream#write(int)
+ */
+ @Override
+ public native void write(int arg0) throws IOException;
+}
+
diff --git a/poi-examples/src/main/ruby/tests/tc_base_tests.rb b/poi-examples/src/main/ruby/tests/tc_base_tests.rb
new file mode 100644
index 0000000000..33492c7ab7
--- /dev/null
+++ b/poi-examples/src/main/ruby/tests/tc_base_tests.rb
@@ -0,0 +1,100 @@
+# ====================================================================
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ====================================================================
+
+require 'test/unit'
+require 'release/poi4r'
+
+class TC_base_tests < Test::Unit::TestCase
+
+ def setup()
+ end
+
+ def test_get_constant
+ h=Poi4r::HSSFWorkbook.new
+ s=h.createSheet("Sheet1")
+ r=s.createRow(0)
+ c=r.createCell(0)
+ assert_equal(3,Poi4r::HSSFCell.CELL_TYPE_BLANK,"Constant CELL_TYPE_BLANK")
+ end
+
+ def test_base
+ system("rm test.xls")
+ h=Poi4r::HSSFWorkbook.new
+
+ #Test Sheet Creation
+ s=h.createSheet("Sheet1")
+ s=h.createSheet("Sheet2")
+ assert_equal(2,h.getNumberOfSheets(),"Number of sheets is 2")
+
+ #Test setting cell values
+ s=h.getSheetAt(0)
+ r=s.createRow(0)
+ c=r.createCell(0)
+ c.setCellValue(1.5)
+ assert_equal(c.getNumericCellValue(),1.5,"Numeric Cell Value")
+ c=r.createCell(1)
+ c.setCellValue("Ruby")
+ assert_equal(c.getStringCellValue(),"Ruby","String Cell Value")
+ #Test error handling
+ assert_raise (RuntimeError) {c.getNumericCellValue()}
+
+ #Test styles
+ st = h.createCellStyle()
+ c=r.createCell(2)
+ st.setAlignment(Poi4r::HSSFCellStyle.ALIGN_CENTER)
+ c.setCellStyle(st)
+ c.setCellValue("centr'd")
+
+ #Date handling
+ c=r.createCell(3)
+ t1=Time.now
+ c.setCellValue(Time.now)
+ t2= c.getDateCellValue().gmtime
+ assert_equal(t1.year,t2.year,"year")
+ assert_equal(t1.mon,t2.mon,"month")
+ assert_equal(t1.day,t2.day,"day")
+ assert_equal(t1.hour,t2.hour,"hour")
+ assert_equal(t1.min,t2.min,"min")
+ assert_equal(t1.sec,t2.sec,"sec")
+ st=h.createCellStyle();
+ st.setDataFormat(Poi4r::HSSFDataFormat.getBuiltinFormat("m/d/yy h:mm"))
+ c.setCellStyle(st)
+
+ #Fonts
+ c=r.createCell(4)
+ font = h.createFont();
+ font.setFontHeightInPoints(24);
+ font.setFontName("Courier New");
+ font.setItalic(true);
+ font.setStrikeout(true);
+ style = h.createCellStyle();
+ style.setFont(font);
+ c.setCellValue("This is a test of fonts");
+ c.setCellStyle(style);
+
+ #Formulas
+ c=r.createCell(5)
+ c.setCellFormula("A1*2")
+ assert_equal("A1*2",c.getCellFormula,"formula")
+
+ #Test writing
+ h.write(File.new("test.xls","w"))
+ assert_nothing_raised {File.new("test.xls","r")}
+ #h.write(0.1)
+ end
+
+end
diff --git a/poi-examples/src/main/ruby/tests/tc_gc.rb b/poi-examples/src/main/ruby/tests/tc_gc.rb
new file mode 100644
index 0000000000..82c3c2b132
--- /dev/null
+++ b/poi-examples/src/main/ruby/tests/tc_gc.rb
@@ -0,0 +1,32 @@
+# ====================================================================
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ====================================================================
+
+require 'test/unit'
+require 'release/poi4r'
+
+class TC_gc < Test::Unit::TestCase
+ def test_premature_collection
+ h=Poi4r::HSSFWorkbook.new
+ h.createSheet("Sheet1");
+ 5000.times do
+ hh=Poi4r::HSSFWorkbook.new
+ GC.start()
+ end
+ assert_equal(1,h.getNumberOfSheets(),"Number of sheets")
+ end
+end
+
diff --git a/poi-examples/src/main/ruby/tests/ts_all.rb b/poi-examples/src/main/ruby/tests/ts_all.rb
new file mode 100644
index 0000000000..ef50ad5d6d
--- /dev/null
+++ b/poi-examples/src/main/ruby/tests/ts_all.rb
@@ -0,0 +1,20 @@
+# ====================================================================
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ====================================================================
+
+require 'test/unit'
+require 'tests/tc_base_tests'
+require 'tests/tc_gc'
diff --git a/poi-examples/src/main/scala/XSSFMain.scala b/poi-examples/src/main/scala/XSSFMain.scala
new file mode 100644
index 0000000000..3365c903ca
--- /dev/null
+++ b/poi-examples/src/main/scala/XSSFMain.scala
@@ -0,0 +1,56 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+// Import the required classes
+import org.apache.poi.ss.usermodel.{WorkbookFactory, DataFormatter}
+import java.io.{File, FileOutputStream}
+
+object XSSFMain extends App {
+
+ // Automatically convert Java collections to Scala equivalents
+ import scala.collection.JavaConversions._
+
+ // Read the contents of the workbook
+ val workbook = WorkbookFactory.create(new File("SampleSS.xlsx"))
+ val formatter = new DataFormatter()
+ for {
+ // Iterate and print the sheets
+ (sheet, i) <- workbook.zipWithIndex
+ _ = println(s"Sheet $i of ${workbook.getNumberOfSheets}: ${sheet.getSheetName}")
+
+ // Iterate and print the rows
+ row <- sheet
+ _ = println(s"\tRow ${row.getRowNum}")
+
+ // Iterate and print the cells
+ cell <- row
+ } {
+ println(s"\t\t${cell.getCellAddress}: ${formatter.formatCellValue(cell)}")
+ }
+
+ // Add a sheet to the workbook
+ val sheet = workbook.createSheet("new sheet")
+ val row = sheet.createRow(7)
+ val cell = row.createCell(42)
+ cell.setAsActiveCell()
+ cell.setCellValue("The answer to life, the universe, and everything")
+
+ // Save the updated workbook as a new file
+ val fos = new FileOutputStream("SampleSS-updated.xlsx")
+ workbook.write(fos)
+ workbook.close()
+}
diff --git a/poi-examples/src/main/scala/build.sbt b/poi-examples/src/main/scala/build.sbt
new file mode 100644
index 0000000000..598dc28951
--- /dev/null
+++ b/poi-examples/src/main/scala/build.sbt
@@ -0,0 +1,23 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+// Add the POI core and OOXML support dependencies into your build.sbt
+libraryDependencies ++= Seq(
+ "org.apache.poi" % "poi" % "5.0.0",
+ "org.apache.poi" % "poi-ooxml" % "5.0.0",
+ "org.apache.poi" % "poi-ooxml-lite" "5.0.0",
+)
diff --git a/poi-examples/src/test/java/org/apache/poi/integration/TestXLSX2CSV.java b/poi-examples/src/test/java/org/apache/poi/integration/TestXLSX2CSV.java
new file mode 100644
index 0000000000..6863fc9bbe
--- /dev/null
+++ b/poi-examples/src/test/java/org/apache/poi/integration/TestXLSX2CSV.java
@@ -0,0 +1,113 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.integration;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+import org.apache.poi.examples.xssf.eventusermodel.XLSX2CSV;
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.openxml4j.opc.PackageAccess;
+import org.apache.poi.xssf.XSSFTestDataSamples;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public class TestXLSX2CSV {
+ private PrintStream err;
+ private final ByteArrayOutputStream errorBytes = new ByteArrayOutputStream();
+
+ @BeforeEach
+ public void setUp() {
+ // remember and replace default error streams
+ err = System.err;
+
+ PrintStream error = new PrintStream(errorBytes);
+ System.setErr(error);
+ }
+
+ @AfterEach
+ public void tearDown() throws Exception {
+ // restore output-streams again
+ System.setErr(err);
+
+ // Print out found error
+ if (errorBytes.size() > 0) {
+ System.err.println("Had stderr: " + errorBytes.toString("UTF-8"));
+ }
+ }
+
+ @Test
+ public void testNoArgument() throws Exception {
+ // returns with some System.err
+ XLSX2CSV.main(new String[0]);
+
+ String output = errorBytes.toString("UTF-8");
+ assertTrue(output.contains("XLSX2CSV <xlsx file>"), "Had: " + output);
+ }
+
+ @Test
+ public void testInvalidFile() throws Exception {
+ // returns with some System.err
+ XLSX2CSV.main(new String[] { "not-existing-file.xlsx" });
+
+ String output = errorBytes.toString("UTF-8");
+ assertTrue(output.contains("Not found or not a file: not-existing-file.xlsx"), "Had: " + output);
+ }
+
+ @Test
+ public void testSampleFile() throws Exception {
+ final ByteArrayOutputStream outputBytes = new ByteArrayOutputStream();
+ PrintStream out = new PrintStream(outputBytes);
+
+ // The package open is instantaneous, as it should be.
+ try (OPCPackage p = OPCPackage.open(XSSFTestDataSamples.getSampleFile("sample.xlsx").getAbsolutePath(), PackageAccess.READ)) {
+ XLSX2CSV xlsx2csv = new XLSX2CSV(p, out, -1);
+ xlsx2csv.process();
+ }
+
+ String errorOutput = errorBytes.toString("UTF-8");
+ assertEquals(errorOutput.length(), 0);
+
+ String output = outputBytes.toString("UTF-8");
+ assertTrue(output.contains("\"Lorem\",111"), "Had: " + output);
+ assertTrue(output.contains(",\"hello, xssf\",,\"hello, xssf\""), "Had: " + output);
+ }
+
+ @Test
+ public void testMinColumns() throws Exception {
+ final ByteArrayOutputStream outputBytes = new ByteArrayOutputStream();
+ PrintStream out = new PrintStream(outputBytes);
+
+ // The package open is instantaneous, as it should be.
+ try (OPCPackage p = OPCPackage.open(XSSFTestDataSamples.getSampleFile("sample.xlsx").getAbsolutePath(), PackageAccess.READ)) {
+ XLSX2CSV xlsx2csv = new XLSX2CSV(p, out, 5);
+ xlsx2csv.process();
+ }
+
+ String errorOutput = errorBytes.toString("UTF-8");
+ assertEquals(errorOutput.length(), 0);
+
+ String output = outputBytes.toString("UTF-8");
+ assertTrue(output.contains("\"Lorem\",111,,,"), "Had: " + output);
+ assertTrue(output.contains(",\"hello, xssf\",,\"hello, xssf\","), "Had: " + output);
+ }
+}