diff options
author | Andreas Beeker <kiwiwings@apache.org> | 2021-04-07 21:40:33 +0000 |
---|---|---|
committer | Andreas Beeker <kiwiwings@apache.org> | 2021-04-07 21:40:33 +0000 |
commit | b6aee1ef6d3e92a28ffd4b5c03e677b63b43747f (patch) | |
tree | ad9c7b312976c4ed113a7f3b5b4757bfe1b3eee6 /poi-examples | |
parent | 6458acb931a0cc17b2d5ed205a1b3fbbb78b9193 (diff) | |
download | poi-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')
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 -> 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 -> 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 -> 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 <year> + * </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 Binary files differnew file mode 100644 index 0000000000..4e71ba8e65 --- /dev/null +++ b/poi-examples/src/main/java/org/apache/poi/examples/ss/formula/mortgage-calculation.xls 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>◊</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 = " "; + 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 = " "; + } + } + } + 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:
+ * <repositories>
+ * <repository>
+ * <id>xuggle repo</id>
+ * <url>http://xuggle.googlecode.com/svn/trunk/repo/share/java/</url>
+ * </repository>
+ * </repositories>
+ * ...
+ * <dependency>
+ * <groupId>xuggle</groupId>
+ * <artifactId>xuggle-xuggler</artifactId>
+ * <version>5.4</version>
+ * </dependency>
+ *
+ * @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 Binary files differnew file mode 100644 index 0000000000..e4d2613046 --- /dev/null +++ b/poi-examples/src/main/java/org/apache/poi/examples/xslf/bar-chart-template.pptx 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 Binary files differnew file mode 100644 index 0000000000..33d28e154c --- /dev/null +++ b/poi-examples/src/main/java/org/apache/poi/examples/xslf/pie-chart-template.pptx 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 -> 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 -> 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 <year> + * </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 Binary files differnew file mode 100644 index 0000000000..ddd57ef0a3 --- /dev/null +++ b/poi-examples/src/main/java/org/apache/poi/examples/xwpf/usermodel/bar-chart-template.docx diff --git a/poi-examples/src/main/java9/module-info.class b/poi-examples/src/main/java9/module-info.class Binary files differnew file mode 100644 index 0000000000..99c4f271f9 --- /dev/null +++ b/poi-examples/src/main/java9/module-info.class 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); + } +} |