adjusted legal info
diff --git a/jenkins.build.config.xml b/jenkins.build.config.xml index 8c9f500..e93417d 100644 --- a/jenkins.build.config.xml +++ b/jenkins.build.config.xml
@@ -16,6 +16,8 @@ <!-- DO NOT EDIT BELOW THIS LINE --> <jenkins.build.dependencies> <jenkins.build.dependency>org.eclipse.osbp.blob</jenkins.build.dependency> + <jenkins.build.dependency>org.eclipse.osbp.bpm.api</jenkins.build.dependency> + <jenkins.build.dependency>org.eclipse.osbp.runtime</jenkins.build.dependency> <jenkins.build.dependency>org.eclipse.osbp.ui.api</jenkins.build.dependency> <jenkins.build.dependency>org.eclipse.osbp.xtext.datamart.common</jenkins.build.dependency> <jenkins.build.dependency>org.eclipse.osbp.xtext.i18n</jenkins.build.dependency>
diff --git a/org.eclipse.osbp.xtext.table.common.feature/feature.xml b/org.eclipse.osbp.xtext.table.common.feature/feature.xml index b0f2def..151c8c4 100644 --- a/org.eclipse.osbp.xtext.table.common.feature/feature.xml +++ b/org.eclipse.osbp.xtext.table.common.feature/feature.xml
@@ -15,7 +15,7 @@ label="%featureName" version="0.9.0.qualifier" provider-name="%providerName" - plugin="org.eclipse.osbp.xtext.table.common"> + plugin="org.eclipse.osbp.license"> <description> %description
diff --git a/org.eclipse.osbp.xtext.table.common/.classpath b/org.eclipse.osbp.xtext.table.common/.classpath index 43b9862..442b7f3 100644 --- a/org.eclipse.osbp.xtext.table.common/.classpath +++ b/org.eclipse.osbp.xtext.table.common/.classpath
@@ -2,6 +2,8 @@ <classpath> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> - <classpathentry kind="src" path="src"/> + <classpathentry kind="src" path="src/"/> + <classpathentry exported="true" kind="lib" path="lib/easytable-0.4.0.jar"/> + <classpathentry exported="true" kind="lib" path="lib/easytable-0.4.0-sources.jar"/> <classpathentry kind="output" path="target/classes"/> </classpath>
diff --git a/org.eclipse.osbp.xtext.table.common/META-INF/MANIFEST.MF b/org.eclipse.osbp.xtext.table.common/META-INF/MANIFEST.MF index 0716335..d930d31 100644 --- a/org.eclipse.osbp.xtext.table.common/META-INF/MANIFEST.MF +++ b/org.eclipse.osbp.xtext.table.common/META-INF/MANIFEST.MF
@@ -18,12 +18,23 @@ org.eclipse.osbp.ui.api, org.eclipse.e4.core.contexts, org.apache.commons.lang;bundle-version="2.6.0", - org.eclipse.osbp.blob;bundle-version="0.9.0" + org.eclipse.osbp.blob;bundle-version="0.9.0", + org.eclipse.osbp.bpm.api, + org.apache.pdfbox;bundle-version="2.0.6", + org.apache.pdfbox.fontbox;bundle-version="2.0.6", + org.apache.commons.lang3;bundle-version="3.4.0", + org.apache.poi;bundle-version="3.9.0", + org.eclipse.osbp.runtime.common Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Bundle-ActivationPolicy: lazy Import-Package: mondrian.olap, org.eclipse.osbp.xtext.datamart.common.olap;version="0.9.0", org.eclipse.osbp.xtext.i18n;version="0.9.0", + org.eclipse.xtext.xbase.lib;version="2.11.0", org.slf4j -Export-Package: org.eclipse.osbp.xtext.table.common;version="0.9.0" +Export-Package: org.eclipse.osbp.xtext.table.common;version="0.9.0", + org.eclipse.osbp.xtext.table.common.export;version="0.9.0" Bundle-Vendor: Eclipse OSBP +Bundle-ClassPath: ., + lib/easytable-0.4.0.jar, + lib/easytable-0.4.0-sources.jar
diff --git a/org.eclipse.osbp.xtext.table.common/build.properties b/org.eclipse.osbp.xtext.table.common/build.properties index ff9e7df..ac81233 100644 --- a/org.eclipse.osbp.xtext.table.common/build.properties +++ b/org.eclipse.osbp.xtext.table.common/build.properties
@@ -1,12 +1,18 @@ source.. = src/ output.. = target/classes/ -bin.includes = about.properties, about.mappings, about.ini, about.html, META-INF/,\ +bin.includes = about.properties,\ + about.mappings,\ + about.ini,\ + about.html,\ + META-INF/,\ .,\ .settings/,\ plugin.xml,\ license.html,\ LICENSE.txt,\ - epl-2.0.html + epl-2.0.html,\ + lib/,\ + notice.html src.includes = about.properties, about.mappings, about.ini, about.html, license.html,\ LICENSE.txt,\ epl-2.0.html
diff --git a/org.eclipse.osbp.xtext.table.common/lib/easytable-0.4.0-sources.jar b/org.eclipse.osbp.xtext.table.common/lib/easytable-0.4.0-sources.jar new file mode 100644 index 0000000..cc90b2e --- /dev/null +++ b/org.eclipse.osbp.xtext.table.common/lib/easytable-0.4.0-sources.jar Binary files differ
diff --git a/org.eclipse.osbp.xtext.table.common/lib/easytable-0.4.0.jar b/org.eclipse.osbp.xtext.table.common/lib/easytable-0.4.0.jar new file mode 100644 index 0000000..2069e48 --- /dev/null +++ b/org.eclipse.osbp.xtext.table.common/lib/easytable-0.4.0.jar Binary files differ
diff --git a/org.eclipse.osbp.xtext.table.common/pom.xml b/org.eclipse.osbp.xtext.table.common/pom.xml index eed5191..def6129 100644 --- a/org.eclipse.osbp.xtext.table.common/pom.xml +++ b/org.eclipse.osbp.xtext.table.common/pom.xml
@@ -2,47 +2,66 @@ <!--#======================================================================= --> <!--# Copyright (c) 2011, 2016 - Loetz GmbH&Co.KG (69115 Heidelberg, Germany) --> <!--# All rights reserved. This program and the accompanying materials --> -<!--# are made available under the terms of the Eclipse Public License 2.0 --> +<!--# are made available under the terms of the Eclipse Public License 2.0 --> <!--# which accompanies this distribution, and is available at --> -<!--# https://www.eclipse.org/legal/epl-2.0/ --> -<!--# --> -<!--# SPDX-License-Identifier: EPL-2.0 --> +<!--# https://www.eclipse.org/legal/epl-2.0/ --> +<!--# --> +<!--# SPDX-License-Identifier: EPL-2.0 --> <!--# --> <!--# Contributors: --> -<!--# Christophe Loetz (Loetz GmbH&Co.KG) - initial API and implementation --> +<!--# Christophe Loetz (Loetz GmbH&Co.KG) - initial API and implementation --> <!--#======================================================================= --> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - <parent> - <groupId>org.eclipse.osbp.xtext.table.common</groupId> - <artifactId>org.eclipse.osbp.xtext.table.common.aggregator</artifactId> - <version>0.9.0-SNAPSHOT</version> - <relativePath>..</relativePath> - </parent> - <artifactId>org.eclipse.osbp.xtext.table.common</artifactId> - <build> - <sourceDirectory>emf-gen</sourceDirectory> - <resources> - <resource> - <directory>src</directory> - <excludes> - <exclude>**/*.java</exclude> - </excludes> - </resource> - <resource> - <directory>src-gen</directory> - <excludes> - <exclude>**/*.java</exclude> - </excludes> - </resource> - <resource> - <directory>xtend-gen</directory> - <excludes> - <exclude>**/*.java</exclude> - </excludes> - </resource> - </resources> - </build> - <packaging>eclipse-plugin</packaging> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.eclipse.osbp.xtext.table.common</groupId> + <artifactId>org.eclipse.osbp.xtext.table.common.aggregator</artifactId> + <version>0.9.0-SNAPSHOT</version> + <relativePath>..</relativePath> + </parent> + <artifactId>org.eclipse.osbp.xtext.table.common</artifactId> + <packaging>eclipse-plugin</packaging> + + <dependencies> + <!-- https://github.com/vandeseer/easytable --> + <!-- CQ: https://dev.eclipse.org/ipzilla/show_bug.cgi?id=19223 --> + <dependency> + <groupId>com.github.vandeseer</groupId> + <artifactId>easytable</artifactId> + <version>0.4.0</version> + </dependency> + <dependency> + <groupId>com.github.vandeseer</groupId> + <artifactId>easytable</artifactId> + <version>0.4.0</version> + <classifier>sources</classifier> + </dependency> + </dependencies> + + <build> + <sourceDirectory>emf-gen</sourceDirectory> + <resources> + <resource> + <directory>src</directory> + <excludes> + <exclude>**/*.java</exclude> + </excludes> + </resource> + <resource> + <directory>src-gen</directory> + <excludes> + <exclude>**/*.java</exclude> + </excludes> + </resource> + <resource> + <directory>xtend-gen</directory> + <excludes> + <exclude>**/*.java</exclude> + </excludes> + </resource> + </resources> + </build> + </project>
diff --git a/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/CellSetImage.java b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/CellSetImage.java index b95da12..8de80e2 100644 --- a/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/CellSetImage.java +++ b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/CellSetImage.java
@@ -25,14 +25,16 @@ public class CellSetImage extends FormLayout implements Comparable<CellSetImage> { private static final long serialVersionUID = 4873534419157818152L; private Object value = null; + private String resourceName; public Object getValue() { return value; } - public CellSetImage(Object value, String caption, Resource resource, boolean hideLabel, String sizeString) { + public CellSetImage(Object value, String caption, Resource resource, String resourceName, boolean hideLabel, String sizeString) { super(); this.value = value; + this.resourceName = resourceName; setSpacing(false); setMargin(new MarginInfo(false, false, false, false)); Image img = null; @@ -62,4 +64,8 @@ } return 0; } + + public String getResourceName() { + return resourceName; + } }
diff --git a/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/CellSetIndexedContainer.java b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/CellSetIndexedContainer.java index d8908d0..ca03ee0 100644 --- a/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/CellSetIndexedContainer.java +++ b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/CellSetIndexedContainer.java
@@ -27,6 +27,8 @@ import org.eclipse.e4.core.contexts.IEclipseContext; import org.eclipse.osbp.blob.component.BlobUploadComponent; +import org.eclipse.osbp.bpm.api.BPMStatus; +import org.eclipse.osbp.runtime.common.historized.UUIDHist; import org.eclipse.osbp.ui.api.customfields.IBlobService; import org.eclipse.osbp.ui.api.metadata.IDSLMetadataService; import org.eclipse.osbp.ui.api.themes.IThemeResourceService; @@ -674,6 +676,12 @@ } DerivedCell cell = getCell(itemId, columnName, null); if (cell != null) { + if(columnName.contains("__id__")) { + String currentCellName = columnName.replace("__id__", "__validfrom__"); + if(getCell(itemId, currentCellName, null) != null) { + return new UUIDHist((String)cell.getValue(), (long)getCell(itemId, currentCellName, null).getValue()); + } + } return cell.getValue(); } return null; @@ -712,6 +720,15 @@ return null; } + public BPMStatus getTaskStatus(int itemId) { + DerivedCell cell = getCell(itemId, "status", null); + if (cell != null) { + Object value = cell.getValue(); + return BPMStatus.values()[(int)value]; + } + return BPMStatus.Obsolete; + } + public String getCellTitle(int itemId, String columnName) { String fullTitle = ""; List<Integer> coordinate = new ArrayList<>(getCoordinateSystem());
diff --git a/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/PropertyLookup.java b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/PropertyLookup.java index 4ee59dd..4e01adc 100644 --- a/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/PropertyLookup.java +++ b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/PropertyLookup.java
@@ -29,6 +29,7 @@ import org.eclipse.osbp.ui.api.metadata.IDSLMetadataService; import org.eclipse.osbp.ui.api.themes.IThemeResourceService; import org.eclipse.osbp.ui.api.themes.IThemeResourceService.ThemeResourceType; +import org.eclipse.xtext.xbase.lib.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -90,16 +91,16 @@ boolean hideLabel = false; boolean collapseColumn = false; String tooltipPattern = null; - private Map<Date, Resource> dateResourceMap = new TreeMap<>(new DateComparator()); + private Map<Date, Pair<Resource,String>> dateResourceMap = new TreeMap<>(new DateComparator()); private Map<Date, String> dateStyleMap = new TreeMap<>(new DateComparator()); private Map<Date, String> dateTooltipMap = new TreeMap<>(new DateComparator()); - private Map<Double, Resource> doubleResourceMap = new TreeMap<>(new DoubleComparator()); + private Map<Double, Pair<Resource,String>> doubleResourceMap = new TreeMap<>(new DoubleComparator()); private Map<Double, String> doubleStyleMap = new TreeMap<>(new DoubleComparator()); private Map<Double, String> doubleTooltipMap = new TreeMap<>(new DoubleComparator()); - private Map<Integer, Resource> intResourceMap = new TreeMap<>(new IntegerComparator()); + private Map<Integer, Pair<Resource,String>> intResourceMap = new TreeMap<>(new IntegerComparator()); private Map<Integer, String> intStyleMap = new TreeMap<>(new IntegerComparator()); private Map<Integer, String> intTooltipMap = new TreeMap<>(new IntegerComparator()); - private Map<String, Resource> stringResourceMap = new HashMap<>(); + private Map<String, Pair<Resource,String>> stringResourceMap = new HashMap<>(); private Map<String, String> stringStyleMap = new HashMap<>(); private Map<String, String> stringTooltipMap = new HashMap<>(); private Locale locale; @@ -119,7 +120,6 @@ private Resource columnIcon = null; private int resolutionId = 0; private IBlobService blobService; - @SuppressWarnings("rawtypes") private Class<?> enumClass; public PropertyLookup(IThemeResourceService themeResourceService, IDSLMetadataService dslMetadataService, @@ -197,13 +197,13 @@ break; case STRING: item = (String) value; - LOGGER.debug("getTooltip >" + item + "<"); + LOGGER.debug("getTooltip >{}<", item); break; default: break; } if (tooltipPattern != null) { - LOGGER.debug("getTooltip pattern >" + tooltipPattern + "< result:" + tooltip); + LOGGER.debug("getTooltip pattern >{}< result:{}", tooltipPattern, tooltip); tooltip = String.format(tooltipPattern, item); } else if (value != null) { tooltip = item; @@ -234,7 +234,6 @@ return isEnum; } - @SuppressWarnings("rawtypes") public PropertyLookup setEnum(boolean isEnum, Class<?> enumClass) { this.isEnum = isEnum; this.enumClass = enumClass; @@ -272,7 +271,7 @@ */ public PropertyLookup addResourceInterval(Date until, String resourceName) { Resource resource = themeResourceService.getThemeResource(resourceName, ThemeResourceType.ICON); - dateResourceMap.put(until, resource); + dateResourceMap.put(until, new Pair(resource, resourceName)); isImage = true; defaultType = DATE; return this; @@ -310,7 +309,7 @@ public PropertyLookup addResourceLookup(String value, String resourceName) { Resource resource = themeResourceService.getThemeResource(resourceName, ThemeResourceType.ICON); - stringResourceMap.put(value, resource); + stringResourceMap.put(value, new Pair(resource, resourceName)); isImage = true; defaultType = STRING; return this; @@ -348,7 +347,7 @@ public PropertyLookup addResourceInterval(int until, String resourceName) { Resource resource = themeResourceService.getThemeResource(resourceName, ThemeResourceType.ICON); - intResourceMap.put(until, resource); + intResourceMap.put(until, new Pair(resource, resourceName)); isImage = true; defaultType = INTEGER; return this; @@ -386,7 +385,7 @@ public PropertyLookup addResourceInterval(double until, String resourceName) { Resource resource = themeResourceService.getThemeResource(resourceName, ThemeResourceType.ICON); - doubleResourceMap.put(until, resource); + doubleResourceMap.put(until, new Pair(resource, resourceName)); isImage = true; defaultType = NUMBER; return this; @@ -460,13 +459,13 @@ if ((resourceDiscreteValues && ((Date) value).equals(key)) || (!resourceDiscreteValues && ((Date) value).before(key))) { return new CellSetImage(value, dateConv.convertToPresentation((Date) value, String.class, locale), - dateResourceMap.get(key), hideLabel, resizeString); + dateResourceMap.get(key).getKey(), dateResourceMap.get(key).getValue(), hideLabel, resizeString); } } // if it should be an image and no match was found, return an empty // image to avoid complaints if (isImage) { - return new CellSetImage(value, dateConv.convertToPresentation((Date) value, String.class, locale), null, + return new CellSetImage(value, dateConv.convertToPresentation((Date) value, String.class, locale), null, null, hideLabel, resizeString); } break; @@ -476,7 +475,7 @@ if ((resourceDiscreteValues && doubleValue == key) || (!resourceDiscreteValues && doubleValue <= key)) { return new CellSetImage(doubleValue, numberConv.convertToPresentation(doubleValue, String.class, locale), - doubleResourceMap.get(key), hideLabel, resizeString); + doubleResourceMap.get(key).getKey(), doubleResourceMap.get(key).getValue(), hideLabel, resizeString); } } if (imagePath != null) { @@ -486,14 +485,14 @@ } Resource res = themeResourceService.getThemeResource(path, ThemeResourceType.ICON); return new CellSetImage(doubleValue, - numberConv.convertToPresentation(doubleValue, String.class, locale), res, hideLabel, + numberConv.convertToPresentation(doubleValue, String.class, locale), res, path, hideLabel, resizeString); } // if it should be an image and no match was found, return an empty // image to avoid complaints if (isImage) { return new CellSetImage(doubleValue, - numberConv.convertToPresentation(doubleValue, String.class, locale), null, hideLabel, + numberConv.convertToPresentation(doubleValue, String.class, locale), null, null, hideLabel, resizeString); } break; @@ -502,7 +501,7 @@ for (Integer key : intResourceMap.keySet()) { if ((resourceDiscreteValues && intValue == key) || (!resourceDiscreteValues && intValue <= key)) { return new CellSetImage(intValue, intConv.convertToPresentation(intValue, String.class, locale), - intResourceMap.get(key), hideLabel, resizeString); + intResourceMap.get(key).getKey(), intResourceMap.get(key).getValue(), hideLabel, resizeString); } } if (imagePath != null) { @@ -511,13 +510,13 @@ path = path.replace(imageParameterPattern, String.format(imageParameterFormat, intValue)); } Resource res = themeResourceService.getThemeResource(path, ThemeResourceType.ICON); - return new CellSetImage(intValue, intConv.convertToPresentation(intValue, String.class, locale), res, + return new CellSetImage(intValue, intConv.convertToPresentation(intValue, String.class, locale), res, path, hideLabel, resizeString); } // if it should be an image and no match was found, return an empty // image to avoid complaints if (isImage) { - return new CellSetImage(intValue, intConv.convertToPresentation(intValue, String.class, locale), null, + return new CellSetImage(intValue, intConv.convertToPresentation(intValue, String.class, locale), null, null, hideLabel, resizeString); } if (isEnum) { @@ -531,7 +530,7 @@ if ((resourceDiscreteValues && longValue == (long) key) || (!resourceDiscreteValues && longValue <= (long) key)) { return new CellSetImage(longValue, longConv.convertToPresentation(longValue, String.class, locale), - intResourceMap.get(key), hideLabel, resizeString); + intResourceMap.get(key).getKey(), intResourceMap.get(key).getValue(), hideLabel, resizeString); } } if (imagePath != null) { @@ -541,14 +540,14 @@ String.format(imageParameterFormat, longValue.intValue())); } Resource res = themeResourceService.getThemeResource(path, ThemeResourceType.ICON); - return new CellSetImage(longValue, longConv.convertToPresentation(longValue, String.class, locale), res, + return new CellSetImage(longValue, longConv.convertToPresentation(longValue, String.class, locale), res, path, hideLabel, resizeString); } // if it should be an image and no match was found, return an empty // image to avoid complaints if (isImage) { return new CellSetImage(longValue, longConv.convertToPresentation(longValue, String.class, locale), - null, hideLabel, resizeString); + null, null, hideLabel, resizeString); } break; case BIGDECIMAL: @@ -559,7 +558,7 @@ || (!resourceDiscreteValues && bigValue.compareTo(bdKey) <= 0)) { return new CellSetImage(bigValue, bigDecimalConv.convertToPresentation(bigValue, String.class, locale), - doubleResourceMap.get(key), hideLabel, resizeString); + doubleResourceMap.get(key).getKey(), doubleResourceMap.get(key).getValue(), hideLabel, resizeString); } } if (imagePath != null) { @@ -569,19 +568,19 @@ } Resource res = themeResourceService.getThemeResource(path, ThemeResourceType.ICON); return new CellSetImage(bigValue, bigDecimalConv.convertToPresentation(bigValue, String.class, locale), - res, hideLabel, resizeString); + res, path, hideLabel, resizeString); } // if it should be an image and no match was found, return an empty // image to avoid complaints if (isImage) { return new CellSetImage(bigValue, bigDecimalConv.convertToPresentation(bigValue, String.class, locale), - null, hideLabel, resizeString); + null, null, hideLabel, resizeString); } break; case STRING: for (String key : stringResourceMap.keySet()) { if (key.equals(value)) { - return new CellSetImage(value, (String) value, stringResourceMap.get(key), hideLabel, resizeString); + return new CellSetImage(value, (String) value, stringResourceMap.get(key).getKey(), stringResourceMap.get(key).getValue(), hideLabel, resizeString); } } if (imagePath != null) { @@ -590,7 +589,7 @@ path = path.replace(imageParameterPattern, String.format(imageParameterFormat, (String) value)); } Resource res = themeResourceService.getThemeResource(path, ThemeResourceType.ICON); - return new CellSetImage(value, (String) value, res, hideLabel, resizeString); + return new CellSetImage(value, (String) value, res, path, hideLabel, resizeString); } if (isBlob) { return new BlobComponent(blobService, (String) value, resolutionId); @@ -598,7 +597,7 @@ // if it should be an image and no match was found, return an empty // image to avoid complaints if (isImage) { - return new CellSetImage(value, (String) value, null, hideLabel, resizeString); + return new CellSetImage(value, (String) value, null, null, hideLabel, resizeString); } break; default:
diff --git a/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/CsvExport.java b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/CsvExport.java new file mode 100644 index 0000000..ee9b9f9 --- /dev/null +++ b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/CsvExport.java
@@ -0,0 +1,113 @@ +/** + * Copyright 2011-2019 Jonathan Nash and others + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Contributors: + * Jonathan Nash - initial implementation + * Compex Systemhaus GmbH - adaptions for OSBP + */ +package org.eclipse.osbp.xtext.table.common.export; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.logging.Logger; + +import org.apache.poi.poifs.filesystem.POIFSFileSystem; +import org.eclipse.osbp.ui.api.themes.IThemeResourceService; +import org.tepi.filtertable.FilterTable; + +public class CsvExport extends ExcelExport { + private static final long serialVersionUID = 935966816321924835L; + private static final Logger LOGGER = Logger.getLogger(CsvExport.class.getName()); + + public CsvExport(final FilterTable table, IThemeResourceService themeResourceService) { + super(table, themeResourceService); + } + + public CsvExport(final FilterTable table, IThemeResourceService themeResourceService, final String sheetName) { + super(table, themeResourceService, sheetName); + } + + public CsvExport(final FilterTable table, IThemeResourceService themeResourceService, final String sheetName, final String reportTitle) { + super(table, themeResourceService, sheetName, reportTitle); + } + + public CsvExport(final FilterTable table, IThemeResourceService themeResourceService, final String sheetName, final String reportTitle, + final String exportFileName) { + super(table, themeResourceService, sheetName, reportTitle, exportFileName); + } + + public CsvExport(final FilterTable table, IThemeResourceService themeResourceService, final String sheetName, final String reportTitle, + final String exportFileName, final boolean hasTotalsRow) { + super(table, themeResourceService, sheetName, reportTitle, exportFileName, hasTotalsRow); + } + + public CsvExport(final TableHolder tableHolder) { + super(tableHolder); + } + + public CsvExport(final TableHolder tableHolder, final String sheetName) { + super(tableHolder, sheetName); + } + + public CsvExport(final TableHolder tableHolder, final String sheetName, final String reportTitle) { + super(tableHolder, sheetName, reportTitle); + } + + public CsvExport(final TableHolder tableHolder, final String sheetName, final String reportTitle, + final String exportFileName) { + super(tableHolder, sheetName, reportTitle, exportFileName); + } + + public CsvExport(final TableHolder tableHolder, final String sheetName, final String reportTitle, + final String exportFileName, final boolean hasTotalsRow) { + super(tableHolder, sheetName, reportTitle, exportFileName, hasTotalsRow); + } + + @Override + /** + * Convert Excel to CSV and send to user. + * + */ + public boolean sendConverted() { + File tempXlsFile; + File tempCsvFile; + try { + tempXlsFile = File.createTempFile("tmp", ".xls"); + final FileOutputStream fileOut = new FileOutputStream(tempXlsFile); + workbook.write(fileOut); + final FileInputStream fis = new FileInputStream(tempXlsFile); + final POIFSFileSystem fs = new POIFSFileSystem(fis); + tempCsvFile = File.createTempFile("tmp", ".csv"); + final PrintStream p = + new PrintStream(new BufferedOutputStream( + new FileOutputStream(tempCsvFile, true))); + + final XLS2CSVmra xls2csv = new XLS2CSVmra(fs, p, -1); + xls2csv.process(); + p.close(); + if (null == mimeType) { + setMimeType(CSV_MIME_TYPE); + } + return super.sendConvertedFileToUser(getTableHolder().getUI(), tempCsvFile, getReportTitle()+".csv"); + } catch (final IOException e) { + LOGGER.warning("Converting to CSV failed with IOException " + e); + return false; + } + } +}
diff --git a/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/CustomTableExportableColumnGenerator.java b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/CustomTableExportableColumnGenerator.java new file mode 100644 index 0000000..e6ddad8 --- /dev/null +++ b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/CustomTableExportableColumnGenerator.java
@@ -0,0 +1,30 @@ +/** + * Copyright 2011-2019 Jonathan Nash and others + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Contributors: + * Jonathan Nash - initial implementation + * Compex Systemhaus GmbH - adaptions for OSBP + */ +package org.eclipse.osbp.xtext.table.common.export; + +import com.vaadin.data.Property; +import com.vaadin.ui.CustomTable.ColumnGenerator; + +public interface CustomTableExportableColumnGenerator extends ColumnGenerator { + + Property getGeneratedProperty(Object itemId, Object columnId); + // the type of the generated property + Class<?> getType(); +}
diff --git a/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/CustomTableHolder.java b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/CustomTableHolder.java new file mode 100644 index 0000000..cca90ec --- /dev/null +++ b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/CustomTableHolder.java
@@ -0,0 +1,152 @@ +/** + * Copyright 2011-2019 Jonathan Nash and others + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Contributors: + * Jonathan Nash - initial implementation + * Compex Systemhaus GmbH - adaptions for OSBP + */ +package org.eclipse.osbp.xtext.table.common.export; + +import com.vaadin.data.Container; +import com.vaadin.data.Property; +import com.vaadin.ui.CustomTable; +import com.vaadin.ui.CustomTable.Align; +import com.vaadin.ui.CustomTable.ColumnGenerator; +import com.vaadin.ui.UI; +import org.apache.poi.ss.usermodel.CellStyle; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +/** + * @author thomas + */ +public class CustomTableHolder implements TableHolder { + + /** + * Whether the Container is a HierarchicalContainer or an extension thereof. + */ + private boolean hierarchical; + + private CustomTable table; + /** + * The Property ids of the Items in the Table. + */ + private LinkedList<Object> propIds; + + public CustomTableHolder(CustomTable table) { + this.table = table; + this.propIds = new LinkedList<Object>(Arrays.asList(table.getVisibleColumns())); + // fixed issue pointed out by Mark Lillywhite in the forum and smorygo....@gmail.com on the issues page. + // Was comparing to HierarchicalContainer, should have been comparing to Container.Hierarchical. + if (Container.Hierarchical.class.isAssignableFrom(table.getContainerDataSource().getClass())) { + setHierarchical(true); + } else { + setHierarchical(false); + } + } + + @Override + public List<Object> getPropIds() { + return propIds; + } + + @Override + public boolean isHierarchical() { + return hierarchical; + } + + @Override + public final void setHierarchical(boolean hierarchical) { + this.hierarchical = hierarchical; + } + + @Override + public Short getCellAlignment(Object propId) { + final Align vaadinAlignment = table.getColumnAlignment(propId); + return vaadinAlignmentToCellAlignment(vaadinAlignment); + } + + private Short vaadinAlignmentToCellAlignment(final Align vaadinAlignment) { + if (Align.LEFT.equals(vaadinAlignment)) { + return CellStyle.ALIGN_LEFT; + } else if (Align.RIGHT.equals(vaadinAlignment)) { + return CellStyle.ALIGN_RIGHT; + } else { + return CellStyle.ALIGN_CENTER; + } + } + + @Override + public boolean isGeneratedColumn(final Object propId) throws IllegalArgumentException { + return table.getColumnGenerator(propId) != null; + } + + @Override + public Property getPropertyForGeneratedColumn(final Object propId, final Object rootItemId) throws + IllegalArgumentException { + Property prop; + final ColumnGenerator tcg = table.getColumnGenerator(propId); + if (tcg instanceof CustomTableExportableColumnGenerator) { + prop = ((CustomTableExportableColumnGenerator) tcg).getGeneratedProperty(rootItemId, propId); + } else { + prop = null; + } + return prop; + } + + @Override + public Class<?> getPropertyTypeForGeneratedColumn(final Object propId) throws IllegalArgumentException { + Class<?> classType; + final ColumnGenerator tcg = table.getColumnGenerator(propId); + if (tcg instanceof CustomTableExportableColumnGenerator) { + classType = ((CustomTableExportableColumnGenerator) tcg).getType(); + } else { + classType = String.class; + } + return classType; + } + + @Override + public boolean isExportableFormattedProperty() { + return table instanceof ExportableFormattedProperty; + } + + @Override + public boolean isColumnCollapsed(Object propertyId) { + return table.isColumnCollapsed(propertyId); + } + + @Override + public UI getUI() { + return table.getUI(); + } + + @Override + public String getColumnHeader(Object propertyId) { + return table.getColumnHeader(propertyId); + } + + @Override + public Container getContainerDataSource() { + return table.getContainerDataSource(); + } + + @Override + public String getFormattedPropertyValue(Object rowId, Object colId, Property property) { + return ((ExportableFormattedProperty) table).getFormattedPropertyValue(rowId, colId, property); + } +} \ No newline at end of file
diff --git a/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/DefaultTableHolder.java b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/DefaultTableHolder.java new file mode 100644 index 0000000..180d412 --- /dev/null +++ b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/DefaultTableHolder.java
@@ -0,0 +1,205 @@ +/** + * Copyright 2011-2019 Jonathan Nash and others + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Contributors: + * Jonathan Nash - initial implementation + * Compex Systemhaus GmbH - adaptions for OSBP + */ +package org.eclipse.osbp.xtext.table.common.export; + +import com.vaadin.data.Container; +import com.vaadin.data.Property; +import com.vaadin.ui.Grid; +import com.vaadin.ui.UI; +import org.apache.poi.ss.usermodel.CellStyle; +import org.tepi.filtertable.FilterTable; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +/** + * @author thomas + */ +public class DefaultTableHolder implements TableHolder { + + protected short defaultAlignment = CellStyle.ALIGN_LEFT; + + /** + * Whether the Container is a HierarchicalContainer or an extension thereof. + */ + private boolean hierarchical; + + private FilterTable heldTable; + private Grid heldGrid; + private Container container; + /** + * The Property ids of the Items in the FilterTable. + */ + private LinkedList<Object> propIds; + + public DefaultTableHolder(FilterTable table) { + this(table.getContainerDataSource()); + this.heldTable = table; + // The order and visibility of the columns are determined by the FilterTable + this.propIds = new LinkedList<Object>(Arrays.asList(table.getVisibleColumns())); + } + + public DefaultTableHolder(Grid grid) { + this(grid.getContainerDataSource()); + this.heldGrid = grid; + + List<Grid.Column> columns = grid.getColumns(); + this.propIds = new LinkedList<Object>(); + for (Grid.Column c: columns) { + propIds.add(c.getPropertyId()); + } + } + + public DefaultTableHolder(Container container) { + this.container = container; + // fixed issue pointed out by Mark Lillywhite in the forum and smorygo....@gmail.com on the issues page. + // Was comparing to HierarchicalContainer, should have been comparing to Container.Hierarchical. + if (Container.Hierarchical.class.isAssignableFrom(this.container.getClass())) { + setHierarchical(true); + } else { + setHierarchical(false); + } + // The order and visibility of the columns are determined by the Container unless later + // superseded by the FilterTable or the Grid. + this.propIds = new LinkedList<Object>(container.getContainerPropertyIds()); + this.heldTable = null; + this.heldGrid = null; + } + + @Override + public List<Object> getPropIds() { + return propIds; + } + + @Override + public boolean isHierarchical() { + return hierarchical; + } + + @Override + final public void setHierarchical(boolean hierarchical) { + this.hierarchical = hierarchical; + } + + @Override + public Short getCellAlignment(Object propId) { + if (null == heldTable) { + return defaultAlignment; + } + final FilterTable.Align vaadinAlignment = heldTable.getColumnAlignment(propId); + return vaadinAlignmentToCellAlignment(vaadinAlignment); + } + + private Short vaadinAlignmentToCellAlignment(final FilterTable.Align vaadinAlignment) { + if (FilterTable.Align.LEFT.equals(vaadinAlignment)) { + return CellStyle.ALIGN_LEFT; + } else if (FilterTable.Align.RIGHT.equals(vaadinAlignment)) { + return CellStyle.ALIGN_RIGHT; + } else { + return CellStyle.ALIGN_CENTER; + } + } + + @Override + public boolean isGeneratedColumn(final Object propId) throws IllegalArgumentException { + if (null == heldTable) { + return false; + } + return heldTable.getColumnGenerator(propId) != null; + } + + @Override + public Property getPropertyForGeneratedColumn(final Object propId, final Object rootItemId) throws IllegalArgumentException { + Property prop = null; + if (null != heldTable) { + final FilterTable.ColumnGenerator tcg = heldTable.getColumnGenerator(propId); + if (tcg instanceof ExportableColumnGenerator) { + prop = ((ExportableColumnGenerator) tcg).getGeneratedProperty(rootItemId, propId); + } + } + return prop; + } + + @Override + public Class<?> getPropertyTypeForGeneratedColumn(final Object propId) throws IllegalArgumentException { + Class<?> classType = String.class; + if (null != heldTable) { + final FilterTable.ColumnGenerator tcg = heldTable.getColumnGenerator(propId); + if (tcg instanceof ExportableColumnGenerator) { + classType = ((ExportableColumnGenerator) tcg).getType(); + } + } + return classType; + } + + @Override + public boolean isExportableFormattedProperty() { + if (null == heldTable) { + return false; + } + return heldTable instanceof ExportableFormattedProperty; + } + + @Override + public boolean isColumnCollapsed(Object propertyId) { + if (null == heldTable) { + return false; + } + return heldTable.isColumnCollapsed(propertyId); + } + + @Override + public UI getUI() { + if (null != heldTable) { + return heldTable.getUI(); + } + if (null != heldGrid) { + return heldGrid.getUI(); + } + return UI.getCurrent(); + } + + @Override + public String getColumnHeader(Object propertyId) { + if (null == heldTable) { + if (null != heldGrid) { + Grid.Column c = heldGrid.getColumn(propertyId); + return c.getHeaderCaption(); + } else { + return propertyId.toString(); + } + } + return heldTable.getColumnHeader(propertyId).replace(" ", "\n"); + } + + @Override + public Container getContainerDataSource() { + return this.container; + } + + @Override + public String getFormattedPropertyValue(Object rowId, Object colId, Property property) { + if (null == heldTable) { + return ""; + } + return ((ExportableFormattedProperty) heldTable).getFormattedPropertyValue(rowId, colId, property); + } +} \ No newline at end of file
diff --git a/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/DeletingFileInputStream.java b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/DeletingFileInputStream.java new file mode 100644 index 0000000..3e796bd --- /dev/null +++ b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/DeletingFileInputStream.java
@@ -0,0 +1,63 @@ +/** + * Copyright 2011-2019 Jonathan Nash and others + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Contributors: + * Jonathan Nash - initial implementation + * Compex Systemhaus GmbH - adaptions for OSBP + */ +package org.eclipse.osbp.xtext.table.common.export; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.Serializable; + +/** + * This input stream deletes the given file when the InputStream is closed; intended to be used with + * temporary files. + * + * Code obtained from: http://vaadin.com/forum/-/message_boards/view_message/159583 + * + */ +class DeletingFileInputStream extends FileInputStream implements Serializable { + + /** The file. */ + protected File file = null; + + /** + * Instantiates a new deleting file input stream. + * + * @param file + * the file + * @throws FileNotFoundException + * the file not found exception + */ + public DeletingFileInputStream(final File file) throws FileNotFoundException { + super(file); + this.file = file; + } + + /* + * (non-Javadoc) + * + * @see java.io.FileInputStream#close() + */ + @Override + public void close() throws IOException { + super.close(); + file.delete(); + } +}
diff --git a/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/ExcelExport.java b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/ExcelExport.java new file mode 100644 index 0000000..1867901 --- /dev/null +++ b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/ExcelExport.java
@@ -0,0 +1,1386 @@ +/** + * Copyright 2011-2019 Jonathan Nash and others + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Contributors: + * Jonathan Nash - initial implementation + * Compex Systemhaus GmbH - adaptions for OSBP + */ +package org.eclipse.osbp.xtext.table.common.export; + +import com.vaadin.data.Container; +import com.vaadin.data.Property; +import com.vaadin.data.util.ObjectProperty; + +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.ClientAnchor; +import org.apache.poi.ss.usermodel.CreationHelper; +import org.apache.poi.ss.usermodel.DataFormat; +import org.apache.poi.ss.usermodel.Drawing; +import org.apache.poi.ss.usermodel.Font; +import org.apache.poi.ss.usermodel.FormulaEvaluator; +import org.apache.poi.ss.usermodel.IndexedColors; +import org.apache.poi.ss.usermodel.Picture; +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.ss.util.CellUtil; +import org.apache.poi.ss.util.RegionUtil; +import org.apache.poi.util.IOUtils; +import org.eclipse.osbp.ui.api.themes.IThemeResourceService; +import org.eclipse.osbp.ui.api.themes.IThemeResourceService.ThemeResourceType; +import org.eclipse.osbp.xtext.table.common.CellSetImage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.tepi.filtertable.FilterTable; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigDecimal; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * The Class ExcelExport. Implementation of TableExport to export Vaadin Tables to Excel .xls files. + * + * @author jnash + * @version $Revision: 1.2 $ + */ +public class ExcelExport extends TableExport { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = -8404407996727936497L; + private static final Logger LOGGER = LoggerFactory.getLogger(ExcelExport.class); + + /** + * The name of the sheet in the workbook the table contents will be written to. + */ + protected String sheetName; + + /** + * The title of the "report" of the table contents. + */ + protected String reportTitle; + + /** + * The filename of the workbook that will be sent to the user. + */ + protected String exportFileName; + + /** + * Flag indicating whether we will add a totals row to the FilterTable. A totals row in the FilterTable is + * typically implemented as a footer and therefore is not part of the data source. + */ + protected boolean displayTotals; + + /** + * Flag indicating whether the first column should be treated as row headers. They will then be + * formatted either like the column headers or a special row headers CellStyle can be specified. + */ + protected boolean rowHeaders = false; + + /** + * Flag indicating whether we should use table.formatPropertyValue() as the cell value instead + * of the property value using the specified data formats. + */ + protected boolean useTableFormatPropertyValue = false; + + /** + * The workbook that contains the sheet containing the report with the table contents. + */ + protected final transient Workbook workbook; + + /** + * The Sheet object that will contain the table contents report. + */ + protected transient Sheet sheet; + protected transient Sheet hierarchicalTotalsSheet = null; + + /** + * The POI cell creation helper. + */ + protected transient CreationHelper createHelper; + protected transient DataFormat dataFormat; + protected transient Drawing drawing; + + /** + * Various styles that are used in report generation. These can be set by the user if the + * default style is not desired to be used. + */ + protected transient CellStyle dateCellStyle; + protected transient CellStyle doubleCellStyle; + protected transient CellStyle integerCellStyle; + protected transient CellStyle totalsDoubleCellStyle; + protected transient CellStyle totalsIntegerCellStyle; + protected transient CellStyle columnHeaderCellStyle; + protected transient CellStyle titleCellStyle; + protected Short dateDataFormat; + protected Short doubleDataFormat; + protected Short integerDataFormat; + protected transient Map<Short, CellStyle> dataFormatCellStylesMap = new HashMap<>(); + + /** + * The default row header style is null and, if row headers are specified with + * setRowHeaders(true), then the column headers style is used. setRowHeaderStyle() allows the + * user to specify a different row header style. + */ + protected transient CellStyle rowHeaderCellStyle = null; + + /** + * The totals row. + */ + protected transient Row titleRow; + protected transient Row headerRow; + protected transient Row totalsRow; + protected transient Row hierarchicalTotalsRow; + // This let's the user specify the data format of the property in case the formatting of the property + // will not be properly identified by the class of the property. In this case, the specified format is + // used. However, all other cell stylings will be those of the + protected transient Map<Object, String> propertyExcelFormatMap = new HashMap<>(); + + /** + * At minimum, we need a FilterTable to export. Everything else has default settings. + * + * @param table the table + */ + public ExcelExport(final FilterTable table, IThemeResourceService themeResourceService) { + this(table, themeResourceService, null); + } + + /** + * Instantiates a new TableExport class. + * + * @param table the table + * @param sheetName the sheet name + */ + public ExcelExport(final FilterTable table, IThemeResourceService themeResourceService, final String sheetName) { + this(table, themeResourceService, sheetName, null); + } + + /** + * Instantiates a new TableExport class. + * + * @param table the table + * @param sheetName the sheet name + * @param reportTitle the report title + */ + public ExcelExport(final FilterTable table, IThemeResourceService themeResourceService, final String sheetName, final String reportTitle) { + this(table, themeResourceService, sheetName, reportTitle, null); + } + + /** + * Instantiates a new TableExport class. + * + * @param table the table + * @param sheetName the sheet name + * @param reportTitle the report title + * @param exportFileName the export file name + */ + public ExcelExport(final FilterTable table, IThemeResourceService themeResourceService, final String sheetName, final String reportTitle, + final String exportFileName) { + this(table, themeResourceService, sheetName, reportTitle, exportFileName, true); + } + + /** + * Instantiates a new TableExport class. This is the final constructor that all other + * constructors end up calling. If the other constructors were called then they pass in the + * default parameters. + * + * @param table the table + * @param sheetName the sheet name + * @param reportTitle the report title + * @param exportFileName the export file name + * @param hasTotalsRow flag indicating whether we should create a totals row + */ + public ExcelExport(final FilterTable table, IThemeResourceService themeResourceService, final String sheetName, final String reportTitle, + final String exportFileName, final boolean hasTotalsRow) { + this(table, themeResourceService, new HSSFWorkbook(), sheetName, reportTitle, exportFileName, hasTotalsRow); + } + + public ExcelExport(final FilterTable table, IThemeResourceService themeResourceService, final Workbook wkbk, final String shtName, final String rptTitle, + final String xptFileName, final boolean hasTotalsRow) { + super(table, themeResourceService); + workbook = wkbk; + init(shtName, rptTitle, xptFileName, hasTotalsRow); + format(); + } + + /** + * At minimum, we need a FilterTable to export. Everything else has default settings. + * + * @param tableHolder the tableHolder + */ + public ExcelExport(final TableHolder tableHolder) { + this(tableHolder, null); + } + + /** + * Instantiates a new TableExport class. + * + * @param tableHolder the tableHolder + * @param sheetName the sheet name + */ + public ExcelExport(final TableHolder tableHolder, final String sheetName) { + this(tableHolder, sheetName, null); + } + + /** + * Instantiates a new TableExport class. + * + * @param tableHolder the tableHolder + * @param sheetName the sheet name + * @param reportTitle the report title + */ + public ExcelExport(final TableHolder tableHolder, final String sheetName, final String reportTitle) { + this(tableHolder, sheetName, reportTitle, null); + } + + /** + * Instantiates a new TableExport class. + * + * @param tableHolder the tableHolder + * @param sheetName the sheet name + * @param reportTitle the report title + * @param exportFileName the export file name + */ + public ExcelExport(final TableHolder tableHolder, final String sheetName, final String reportTitle, + final String exportFileName) { + this(tableHolder, sheetName, reportTitle, exportFileName, true); + } + + /** + * Instantiates a new TableExport class. This is the final constructor that all other + * constructors end up calling. If the other constructors were called then they pass in the + * default parameters. + * + * @param tableHolder the tableHolder + * @param sheetName the sheet name + * @param reportTitle the report title + * @param exportFileName the export file name + * @param hasTotalsRow flag indicating whether we should create a totals row + */ + public ExcelExport(final TableHolder tableHolder, final String sheetName, final String reportTitle, + final String exportFileName, final boolean hasTotalsRow) { + this(tableHolder, new HSSFWorkbook(), sheetName, reportTitle, exportFileName, hasTotalsRow); + } + + public ExcelExport(final TableHolder tableHolder, final Workbook wkbk, final String shtName, + final String rptTitle, final String xptFileName, final boolean hasTotalsRow) { + super(tableHolder); + workbook = wkbk; + init(shtName, rptTitle, xptFileName, hasTotalsRow); + } + + private void init(final String shtName, final String rptTitle, final String xptFileName, + final boolean hasTotalsRow) { + if ((null == shtName) || ("".equals(shtName))) { + sheetName = "FilterTable Export"; + } else { + sheetName = shtName; + } + if (null == rptTitle) { + reportTitle = ""; + } else { + reportTitle = rptTitle; + } + if ((null == xptFileName) || ("".equals(xptFileName))) { + exportFileName = "FilterTable-Export.xls"; + } else { + exportFileName = xptFileName; + } + displayTotals = hasTotalsRow; + + sheet = workbook.createSheet(sheetName); + createHelper = workbook.getCreationHelper(); + dataFormat = workbook.createDataFormat(); + drawing = sheet.createDrawingPatriarch(); + + dateDataFormat = defaultDateDataFormat(); + doubleDataFormat = defaultDoubleDataFormat(); + integerDataFormat = defaultIntegerDataFormat(); + + doubleCellStyle = defaultDataCellStyle(workbook); + doubleCellStyle.setDataFormat(doubleDataFormat); + dataFormatCellStylesMap.put(doubleDataFormat, doubleCellStyle); + + integerCellStyle = defaultDataCellStyle(workbook); + integerCellStyle.setDataFormat(integerDataFormat); + dataFormatCellStylesMap.put(integerDataFormat, integerCellStyle); + + dateCellStyle = defaultDataCellStyle(workbook); + dateCellStyle.setDataFormat(dateDataFormat); + dataFormatCellStylesMap.put(dateDataFormat, dateCellStyle); + + totalsDoubleCellStyle = defaultTotalsDoubleCellStyle(workbook); + totalsIntegerCellStyle = defaultTotalsIntegerCellStyle(workbook); + columnHeaderCellStyle = defaultHeaderCellStyle(workbook); + titleCellStyle = defaultTitleCellStyle(workbook); + } + + /* + * Set a new table to be exported in another workbook tab / sheet. + */ + public void setNextTable(final FilterTable table, final String sheetName) { + setTable(table); + sheet = workbook.createSheet(sheetName); + } + + public void setNextTableHolder(final TableHolder tableHolder, final String sheetName) { + setTableHolder(tableHolder); + sheet = workbook.createSheet(sheetName); + } + + /* + * This will exclude columns from the export that are not visible due to them being collapsed. + * This should be called before convertTable() is called. + */ + public void excludeCollapsedColumns() { + final Iterator<Object> iterator = getPropIds().iterator(); + while (iterator.hasNext()) { + final Object propId = iterator.next(); + if (getTableHolder().isColumnCollapsed(propId)) { + iterator.remove(); + } + } + } + + /** + * Creates the workbook containing the exported table data, without exporting it to the user. + */ + @Override + public void convertTable() { + final int startRow; + // initial setup + initialSheetSetup(); + + // add title row + startRow = addTitleRow(); + int row = startRow; + + // add header row + addHeaderRow(row); + row++; + + // add data rows + if (isHierarchical()) { + row = addHierarchicalDataRows(sheet, row); + } else { + row = addDataRows(sheet, row); + } + + // add totals row + if (displayTotals) { + addTotalsRow(row, startRow); + } + + // final sheet format before export + finalSheetFormat(); + } + + /** + * Export the workbook to the end-user. + * <p/> + * Code obtained from: http://vaadin.com/forum/-/message_boards/view_message/159583 + * + * @return true, if successful + */ + @Override + public boolean sendConverted() { + File tempFile = null; + FileOutputStream fileOut = null; + try { + tempFile = File.createTempFile("tmp", ".xls"); + fileOut = new FileOutputStream(tempFile); + workbook.write(fileOut); + if (null == mimeType) { + setMimeType(EXCEL_MIME_TYPE); + } + return super.sendConvertedFileToUser(getTableHolder().getUI(), tempFile, getReportTitle()+".xls"); + } catch (final IOException e) { + LOGGER.error("Converting to XLS failed with IOException {}", e); + return false; + } finally { + if(tempFile != null) { + tempFile.deleteOnExit(); + } + try { + if(fileOut != null) { + fileOut.close(); + } + } catch (final IOException e) { + // nothing to do + } + } + } + + /** + * Initial sheet setup. Override this method to specifically change initial, sheet-wide, + * settings. + */ + protected void initialSheetSetup() { + final PrintSetup printSetup = sheet.getPrintSetup(); + printSetup.setLandscape(true); + sheet.setFitToPage(true); + sheet.setHorizontallyCenter(true); + if ((isHierarchical()) && (displayTotals)) { + hierarchicalTotalsSheet = workbook.createSheet("tempHts"); + } + } + + /** + * Adds the title row. Override this method to change title-related aspects of the workbook. + * Alternately, the title Row Object is accessible via getTitleRow() after report creation. To + * change title text use setReportTitle(). To change title CellStyle use setTitleStyle(). + * + * @return the int + */ + protected int addTitleRow() { + if ((null == reportTitle) || ("".equals(reportTitle))) { + return 0; + } + titleRow = sheet.createRow(0); + titleRow.setHeightInPoints(45); + final Cell titleCell; + final CellRangeAddress cra; + if (rowHeaders) { + titleCell = titleRow.createCell(1); + cra = new CellRangeAddress(0, 0, 1, getPropIds().size() - 1); + sheet.addMergedRegion(cra); + } else { + titleCell = titleRow.createCell(0); + cra = new CellRangeAddress(0, 0, 0, getPropIds().size() - 1); + sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, getPropIds().size() - 1)); + } + titleCell.setCellValue(reportTitle); + titleCell.setCellStyle(titleCellStyle); + // cell borders don't work on merged ranges so, if there are borders + // we apply them to the merged range here. + if (titleCellStyle.getBorderLeft() != CellStyle.BORDER_NONE) { + RegionUtil.setBorderLeft(titleCellStyle.getBorderLeft(), cra, sheet, workbook); + } + if (titleCellStyle.getBorderRight() != CellStyle.BORDER_NONE) { + RegionUtil.setBorderRight(titleCellStyle.getBorderRight(), cra, sheet, workbook); + } + if (titleCellStyle.getBorderTop() != CellStyle.BORDER_NONE) { + RegionUtil.setBorderTop(titleCellStyle.getBorderTop(), cra, sheet, workbook); + } + if (titleCellStyle.getBorderBottom() != CellStyle.BORDER_NONE) { + RegionUtil.setBorderBottom(titleCellStyle.getBorderBottom(), cra, sheet, workbook); + } + return 1; + } + + /** + * Adds the header row. Override this method to change header-row-related aspects of the + * workbook. Alternately, the header Row Object is accessible via getHeaderRow() after report + * creation. To change header CellStyle, though, use setHeaderStyle(). + * + * @param row the row + */ + protected void addHeaderRow(final int row) { + headerRow = sheet.createRow(row); + Cell headerCell; + Object propId; + headerRow.setHeightInPoints(40); + for (int col = 0; col < getPropIds().size(); col++) { + propId = getPropIds().get(col); + headerCell = headerRow.createCell(col); + headerCell.setCellValue(createHelper.createRichTextString(getTableHolder().getColumnHeader(propId))); + headerCell.setCellStyle(getColumnHeaderStyle(row, col)); + + final Short poiAlignment = getTableHolder().getCellAlignment(propId); + CellUtil.setAlignment(headerCell, workbook, poiAlignment); + } + } + + /** + * This method is called by addTotalsRow() to determine what CellStyle to use. By default we + * just return totalsCellStyle which is either set to the default totals style, or can be + * overriden by the user using setTotalsStyle(). However, if the user wants to have different + * total items have different styles, then this method should be overriden. The parameters + * passed in are all potentially relevant items that may be used to determine what formatting to + * return, that are not accessible globally. + * + * @param row the row + * @param col the current column + * @return the header style + */ + protected CellStyle getColumnHeaderStyle(final int row, final int col) { + if ((rowHeaders) && (col == 0)) { + return titleCellStyle; + } + return columnHeaderCellStyle; + } + + /** + * For Hierarchical Containers, this method recursively adds root items and child items. The + * child items are appropriately grouped using grouping/outlining sheet functionality. Override + * this method to make any changes. To change the CellStyle used for all FilterTable data use + * setDataStyle(). For different data cells to have different CellStyles, override + * getDataStyle(). + * + * @param row the row + * @return the int + */ + protected int addHierarchicalDataRows(final Sheet sheetToAddTo, final int row) { + final Collection<?> roots; + int localRow = row; + roots = ((Container.Hierarchical) getTableHolder().getContainerDataSource()).rootItemIds(); + /* + * For Hierarchical Containers, the outlining/grouping in the sheet is with the summary row + * at the top and the grouped/outlined subcategories below. + */ + sheet.setRowSumsBelow(false); + int count = 0; + for (final Object rootId : roots) { + count = addDataRowRecursively(sheetToAddTo, rootId, localRow); + // for totals purposes, we just want to add rootIds which contain totals + // so we store just the totals in a separate sheet. + if (displayTotals) { + addDataRow(hierarchicalTotalsSheet, rootId, localRow); + } + if (count > 1) { + sheet.groupRow(localRow + 1, (localRow + count) - 1); + sheet.setRowGroupCollapsed(localRow + 1, true); + } + localRow = localRow + count; + } + return localRow; + } + + /** + * this method adds row items for non-Hierarchical Containers. Override this method to make any + * changes. To change the CellStyle used for all FilterTable data use setDataStyle(). For different + * data cells to have different CellStyles, override getDataStyle(). + * + * @param row the row + * @return the int + */ + protected int addDataRows(final Sheet sheetToAddTo, final int row) { + final Collection<?> itemIds = getTableHolder().getContainerDataSource().getItemIds(); + int localRow = row; + int count = 0; + for (final Object itemId : itemIds) { + addDataRow(sheetToAddTo, itemId, localRow); + count = 1; + if (count > 1) { + sheet.groupRow(localRow + 1, (localRow + count) - 1); + sheet.setRowGroupCollapsed(localRow + 1, true); + } + localRow = localRow + count; + } + return localRow; + } + + /** + * Used by addHierarchicalDataRows() to implement the recursive calls. + * + * @param rootItemId the root item id + * @param row the row + * @return the int + */ + private int addDataRowRecursively(final Sheet sheetToAddTo, final Object rootItemId, final int row) { + int numberAdded = 0; + int localRow = row; + addDataRow(sheetToAddTo, rootItemId, row); + numberAdded++; + if (((Container.Hierarchical) getTableHolder().getContainerDataSource()).hasChildren(rootItemId)) { + final Collection<?> children = ((Container.Hierarchical) getTableHolder().getContainerDataSource()) + .getChildren(rootItemId); + for (final Object child : children) { + localRow++; + numberAdded = numberAdded + addDataRowRecursively(sheetToAddTo, child, localRow); + } + } + return numberAdded; + } + + /** + * This method is ultimately used by either addDataRows() or addHierarchicalDataRows() to + * actually add the data to the Sheet. + * + * @param rootItemId the root item id + * @param row the row + */ + + protected void addDataRow(final Sheet sheetToAddTo, final Object rootItemId, final int row) { + final Row sheetRow = sheetToAddTo.createRow(row); + Property<?> prop; + Object propId; + Object value; + Cell sheetCell; + for (int col = 0; col < getPropIds().size(); col++) { + propId = getPropIds().get(col); + prop = getProperty(rootItemId, propId); + if (null == prop) { + value = null; + } else { + value = prop.getValue(); + } + sheetCell = sheetRow.createCell(col); + final CellStyle cs = getCellStyle(rootItemId, row, col, false); + sheetCell.setCellStyle(cs); + final Short poiAlignment = getTableHolder().getCellAlignment(propId); + CellUtil.setAlignment(sheetCell, workbook, poiAlignment); + if (null != value) { + if (!isNumeric(prop.getType())) { + if (java.util.Date.class.isAssignableFrom(prop.getType())) { + sheetCell.setCellValue((Date) value); + } else if(CellSetImage.class.isAssignableFrom(prop.getType())) { + ClientAnchor anchor = createHelper.createClientAnchor(); + anchor.setAnchorType( ClientAnchor.MOVE_AND_RESIZE ); + InputStream stream = getThemeResourceService().getThemeResourceInputStream(((CellSetImage)prop.getValue()).getResourceName(), ThemeResourceType.ICON); + try { + int pictureIndex = workbook.addPicture(IOUtils.toByteArray(stream), Workbook.PICTURE_TYPE_PNG); + anchor.setCol1( col ); + anchor.setRow1( row ); + anchor.setRow2( row ); + anchor.setCol2( col+1 ); + final Picture pict = drawing.createPicture( anchor, pictureIndex ); + pict.resize(); + } catch (IOException e) { + LOGGER.error("{}", e); + } + + } else { + sheetCell.setCellValue(createHelper.createRichTextString(value.toString())); + } + } else { + try { + // parse all numbers as double, the format will determine how they appear + final Double d = Double.parseDouble(value.toString()); + sheetCell.setCellValue(d); + } catch (final NumberFormatException nfe) { + LOGGER.error("NumberFormatException parsing a numeric value: {}", nfe); + sheetCell.setCellValue(createHelper.createRichTextString(value.toString())); + } + } + } + } + } + + private Property<?> getProperty(final Object rootItemId, final Object propId) { + Property<?> prop; + if (getTableHolder().isGeneratedColumn(propId)) { + prop = getTableHolder().getPropertyForGeneratedColumn(propId, rootItemId); + } else { + prop = getTableHolder().getContainerDataSource().getContainerProperty(rootItemId, propId); + if (useTableFormatPropertyValue) { + if (getTableHolder().isExportableFormattedProperty()) { + final String formattedProp = getTableHolder().getFormattedPropertyValue(rootItemId, propId, prop); + if (null == prop) { + prop = new ObjectProperty<>(formattedProp, String.class); + } else { + final Object val = prop.getValue(); + if (null == val) { + prop = new ObjectProperty<>(formattedProp, String.class); + } else { + if (!val.toString().equals(formattedProp)) { + prop = new ObjectProperty<>(formattedProp, String.class); + } + } + } + } else { + LOGGER.error("{}", "Cannot use FilterTable formatted property unless FilterTable is instance of ExportableFormattedProperty"); + } + } + } + return prop; + } + + private Class<?> getPropertyType(final Object propId) { + Class<?> classType; + if (getTableHolder().isGeneratedColumn(propId)) { + classType = getTableHolder().getPropertyTypeForGeneratedColumn(propId); + } else { + classType = getTableHolder().getContainerDataSource().getType(propId); + } + return classType; + } + + public void setExcelFormatOfProperty(final Object propertyId, final String excelFormat) { + if (propertyExcelFormatMap.containsKey(propertyId)) { + propertyExcelFormatMap.remove(propertyId); + } + propertyExcelFormatMap.put(propertyId.toString(), excelFormat); + } + + /** + * This method is called by addDataRow() to determine what CellStyle to use. By default we just + * return dataStyle which is either set to the default data style, or can be overriden by the + * user using setDataStyle(). However, if the user wants to have different data items have + * different styles, then this method should be overriden. The parameters passed in are all + * potentially relevant items that may be used to determine what formatting to return, that are + * not accessible globally. + * + * @param rootItemId the root item id + * @param row the row + * @param col the col + * @return the data style + */ + protected CellStyle getCellStyle(final Object rootItemId, final int row, final int col, final boolean totalsRow) { + final Object propId = getPropIds().get(col); + // get the basic style for the type of cell (i.e. data, header, total) + if ((rowHeaders) && (col == 0)) { + if (null == rowHeaderCellStyle) { + return columnHeaderCellStyle; + } + return rowHeaderCellStyle; + } + final Class<?> propType = getPropertyType(propId); + if (totalsRow) { + if (propertyExcelFormatMap.containsKey(propId)) { + final short df = dataFormat.getFormat(propertyExcelFormatMap.get(propId)); + final CellStyle customTotalStyle = workbook.createCellStyle(); + customTotalStyle.cloneStyleFrom(totalsDoubleCellStyle); + customTotalStyle.setDataFormat(df); + return customTotalStyle; + } + if (isIntegerLongShortOrBigDecimal(propType)) { + return totalsIntegerCellStyle; + } + return totalsDoubleCellStyle; + } + // Check if the user has over-ridden that data format of this property + if (propertyExcelFormatMap.containsKey(propId)) { + final short df = dataFormat.getFormat(propertyExcelFormatMap.get(propId)); + if (dataFormatCellStylesMap.containsKey(df)) { + return dataFormatCellStylesMap.get(df); + } + // if it hasn't already been created for re-use, we create a cell style and override the data format + // For data cells, each data format corresponds to a single complete cell style + final CellStyle retStyle = workbook.createCellStyle(); + retStyle.cloneStyleFrom(dataFormatCellStylesMap.get(doubleDataFormat)); + retStyle.setDataFormat(df); + dataFormatCellStylesMap.put(df, retStyle); + return retStyle; + } + // if not over-ridden, use the overall setting + if (isDoubleOrFloat(propType)) { + return dataFormatCellStylesMap.get(doubleDataFormat); + } else { + if (isIntegerLongShortOrBigDecimal(propType)) { + return dataFormatCellStylesMap.get(integerDataFormat); + } else { + if (java.util.Date.class.isAssignableFrom(propType)) { + return dataFormatCellStylesMap.get(dateDataFormat); + } + } + } + return dataFormatCellStylesMap.get(doubleDataFormat); + } + + /** + * Adds the totals row to the report. Override this method to make any changes. Alternately, the + * totals Row Object is accessible via getTotalsRow() after report creation. To change the + * CellStyle used for the totals row, use setFormulaStyle. For different totals cells to have + * different CellStyles, override getTotalsStyle(). + * + * @param currentRow the current row + * @param startRow the start row + */ + protected void addTotalsRow(final int currentRow, final int startRow) { + totalsRow = sheet.createRow(currentRow); + totalsRow.setHeightInPoints(30); + Cell cell; + CellRangeAddress cra; + for (int col = 0; col < getPropIds().size(); col++) { + final Object propId = getPropIds().get(col); + cell = totalsRow.createCell(col); + cell.setCellStyle(getCellStyle(currentRow, startRow, col, true)); + final Short poiAlignment = getTableHolder().getCellAlignment(propId); + CellUtil.setAlignment(cell, workbook, poiAlignment); + final Class<?> propType = getPropertyType(propId); + if (isNumeric(propType)) { + cra = new CellRangeAddress(startRow, currentRow - 1, col, col); + if (isHierarchical()) { + // 9 & 109 are for sum. 9 means include hidden cells, 109 means exclude. + // this will show the wrong value if the user expands an outlined category, so + // we will range value it first + cell.setCellFormula("SUM(" + cra.formatAsString(hierarchicalTotalsSheet.getSheetName(), + true) + ")"); + } else { + cell.setCellFormula("SUM(" + cra.formatAsString() + ")"); + } + } else { + if (0 == col) { + cell.setCellValue(createHelper.createRichTextString("Total")); + } + } + } + } + + /** + * Final formatting of the sheet upon completion of writing the data. For example, we can only + * size the column widths once the data is in the report and the sheet knows how wide the data + * is. + */ + protected void finalSheetFormat() { + final FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator(); + if (isHierarchical()) { + /* + * evaluateInCell() is equivalent to paste special -> value. The formula refers to cells + * in the other sheet we are going to delete. We sum in the other sheet because if we + * summed in the main sheet, we would double count. Subtotal with hidden rows is not yet + * implemented in POI. + */ + for (final Row r : sheet) { + for (final Cell c : r) { + if (c.getCellType() == Cell.CELL_TYPE_FORMULA) { + evaluator.evaluateInCell(c); + } + } + } + workbook.setActiveSheet(workbook.getSheetIndex(sheet)); + if (hierarchicalTotalsSheet != null) { + workbook.removeSheetAt(workbook.getSheetIndex(hierarchicalTotalsSheet)); + } + } else { + evaluator.evaluateAll(); + } + for (int col = 0; col < getPropIds().size(); col++) { + sheet.autoSizeColumn(col); + } + } + + /** + * Returns the default title style. Obtained from: http://svn.apache.org/repos/asf/poi + * /trunk/src/examples/src/org/apache/poi/ss/examples/TimesheetDemo.java + * + * @param wb the wb + * @return the cell style + */ + protected CellStyle defaultTitleCellStyle(final Workbook wb) { + CellStyle style; + final Font titleFont = wb.createFont(); + titleFont.setFontHeightInPoints((short) 18); + titleFont.setBoldweight(Font.BOLDWEIGHT_BOLD); + style = wb.createCellStyle(); + style.setAlignment(CellStyle.ALIGN_CENTER); + style.setVerticalAlignment(CellStyle.VERTICAL_CENTER); + style.setFont(titleFont); + return style; + } + + /** + * Returns the default header style. Obtained from: http://svn.apache.org/repos/asf/poi + * /trunk/src/examples/src/org/apache/poi/ss/examples/TimesheetDemo.java + * + * @param wb the wb + * @return the cell style + */ + protected CellStyle defaultHeaderCellStyle(final Workbook wb) { + CellStyle style; + final Font monthFont = wb.createFont(); + monthFont.setFontHeightInPoints((short) 11); + monthFont.setColor(IndexedColors.WHITE.getIndex()); + style = wb.createCellStyle(); + style.setAlignment(CellStyle.ALIGN_CENTER); + style.setVerticalAlignment(CellStyle.VERTICAL_CENTER); + style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setFillPattern(CellStyle.SOLID_FOREGROUND); + style.setFont(monthFont); + style.setWrapText(true); + return style; + } + + /** + * Returns the default data cell style. Obtained from: http://svn.apache.org/repos/asf/poi + * /trunk/src/examples/src/org/apache/poi/ss/examples/TimesheetDemo.java + * + * @param wb the wb + * @return the cell style + */ + protected CellStyle defaultDataCellStyle(final Workbook wb) { + CellStyle style; + style = wb.createCellStyle(); + style.setAlignment(CellStyle.ALIGN_CENTER); + style.setWrapText(true); + style.setBorderRight(CellStyle.BORDER_THIN); + style.setRightBorderColor(IndexedColors.BLACK.getIndex()); + style.setBorderLeft(CellStyle.BORDER_THIN); + style.setLeftBorderColor(IndexedColors.BLACK.getIndex()); + style.setBorderTop(CellStyle.BORDER_THIN); + style.setTopBorderColor(IndexedColors.BLACK.getIndex()); + style.setBorderBottom(CellStyle.BORDER_THIN); + style.setBottomBorderColor(IndexedColors.BLACK.getIndex()); + style.setDataFormat(doubleDataFormat); + return style; + } + + /** + * Returns the default totals row style for Double data. Obtained from: http://svn.apache.org/repos/asf/poi + * /trunk/src/examples/src/org/apache/poi/ss/examples/TimesheetDemo.java + * + * @param wb the wb + * @return the cell style + */ + protected CellStyle defaultTotalsDoubleCellStyle(final Workbook wb) { + CellStyle style; + style = wb.createCellStyle(); + style.setAlignment(CellStyle.ALIGN_CENTER); + style.setVerticalAlignment(CellStyle.VERTICAL_CENTER); + style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); + style.setFillPattern(CellStyle.SOLID_FOREGROUND); + style.setDataFormat(doubleDataFormat); + return style; + } + + /** + * Returns the default totals row style for Integer data. Obtained from: http://svn.apache.org/repos/asf/poi + * /trunk/src/examples/src/org/apache/poi/ss/examples/TimesheetDemo.java + * + * @param wb the wb + * @return the cell style + */ + protected CellStyle defaultTotalsIntegerCellStyle(final Workbook wb) { + CellStyle style; + style = wb.createCellStyle(); + style.setAlignment(CellStyle.ALIGN_CENTER); + style.setVerticalAlignment(CellStyle.VERTICAL_CENTER); + style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); + style.setFillPattern(CellStyle.SOLID_FOREGROUND); + style.setDataFormat(integerDataFormat); + return style; + } + + protected short defaultDoubleDataFormat() { + return createHelper.createDataFormat().getFormat("0.00"); + } + + protected short defaultIntegerDataFormat() { + return createHelper.createDataFormat().getFormat("0"); + } + + protected short defaultDateDataFormat() { + return createHelper.createDataFormat().getFormat("mm/dd/yyyy"); + } + + public void setDoubleDataFormat(final String excelDoubleFormat) { + CellStyle prevDoubleDataStyle = null; + if (dataFormatCellStylesMap.containsKey(doubleDataFormat)) { + prevDoubleDataStyle = dataFormatCellStylesMap.get(doubleDataFormat); + dataFormatCellStylesMap.remove(doubleDataFormat); + } + doubleDataFormat = createHelper.createDataFormat().getFormat(excelDoubleFormat); + if (null != prevDoubleDataStyle) { + doubleCellStyle = prevDoubleDataStyle; + doubleCellStyle.setDataFormat(doubleDataFormat); + dataFormatCellStylesMap.put(doubleDataFormat, doubleCellStyle); + } + } + + public void setIntegerDataFormat(final String excelIntegerFormat) { + CellStyle prevIntegerDataStyle = null; + if (dataFormatCellStylesMap.containsKey(integerDataFormat)) { + prevIntegerDataStyle = dataFormatCellStylesMap.get(integerDataFormat); + dataFormatCellStylesMap.remove(integerDataFormat); + } + integerDataFormat = createHelper.createDataFormat().getFormat(excelIntegerFormat); + if (null != prevIntegerDataStyle) { + integerCellStyle = prevIntegerDataStyle; + integerCellStyle.setDataFormat(integerDataFormat); + dataFormatCellStylesMap.put(integerDataFormat, integerCellStyle); + } + } + + public void setDateDataFormat(final String excelDateFormat) { + CellStyle prevDateDataStyle = null; + if (dataFormatCellStylesMap.containsKey(dateDataFormat)) { + prevDateDataStyle = dataFormatCellStylesMap.get(dateDataFormat); + dataFormatCellStylesMap.remove(dateDataFormat); + } + dateDataFormat = createHelper.createDataFormat().getFormat(excelDateFormat); + if (null != prevDateDataStyle) { + dateCellStyle = prevDateDataStyle; + dateCellStyle.setDataFormat(dateDataFormat); + dataFormatCellStylesMap.put(dateDataFormat, dateCellStyle); + } + } + + /** + * Utility method to determine whether value being put in the Cell is numeric. + * + * @param type the type + * @return true, if is numeric + */ + private boolean isNumeric(final Class<?> type) { + if (isIntegerLongShortOrBigDecimal(type)) { + return true; + } + return isDoubleOrFloat(type); + } + + /** + * Utility method to determine whether value being put in the Cell is integer-like type. + * + * @param type the type + * @return true, if is integer-like + */ + private boolean isIntegerLongShortOrBigDecimal(final Class<?> type) { + if ((Integer.class.equals(type) || (int.class.equals(type)))) { + return true; + } + if ((Long.class.equals(type) || (long.class.equals(type)))) { + return true; + } + if ((Short.class.equals(type)) || (short.class.equals(type))) { + return true; + } + return BigDecimal.class.equals(type); + } + + /** + * Utility method to determine whether value being put in the Cell is double-like type. + * + * @param type the type + * @return true, if is double-like + */ + private boolean isDoubleOrFloat(final Class<?> type) { + if ((Double.class.equals(type)) || (double.class.equals(type))) { + return true; + } + return ((Float.class.equals(type)) || (float.class.equals(type))); + } + + /** + * Gets the workbook. + * + * @return the workbook + */ + public Workbook getWorkbook() { + return workbook; + } + + /** + * Gets the sheet name. + * + * @return the sheet name + */ + public String getSheetName() { + return sheetName; + } + + /** + * Gets the report title. + * + * @return the report title + */ + public String getReportTitle() { + return reportTitle; + } + + /** + * Gets the export file name. + * + * @return the export file name + */ + public String getExportFileName() { + return exportFileName; + } + + /** + * Gets the cell style used for report data.. + * + * @return the cell style + */ + public CellStyle getDoubleDataStyle() { + return doubleCellStyle; + } + + /** + * Gets the cell style used for report data.. + * + * @return the cell style + */ + public CellStyle getIntegerDataStyle() { + return integerCellStyle; + } + + public CellStyle getDateDataStyle() { + return dateCellStyle; + } + + /** + * Gets the cell style used for the report headers. + * + * @return the column header style + */ + public CellStyle getColumnHeaderStyle() { + return columnHeaderCellStyle; + } + + /** + * Gets the cell title used for the report title. + * + * @return the title style + */ + public CellStyle getTitleStyle() { + return titleCellStyle; + } + + /** + * Sets the text used for the report title. + * + * @param reportTitle the new report title + */ + public void setReportTitle(final String reportTitle) { + this.reportTitle = reportTitle; + } + + /** + * Sets the export file name. + * + * @param exportFileName the new export file name + */ + public void setExportFileName(final String exportFileName) { + this.exportFileName = exportFileName; + } + + /** + * Sets the cell style used for report data. + * + * @param doubleDataStyle the new data style + */ + public void setDoubleDataStyle(final CellStyle doubleDataStyle) { + this.doubleCellStyle = doubleDataStyle; + } + + /** + * Sets the cell style used for report data. + * + * @param integerDataStyle the new data style + */ + public void setIntegerDataStyle(final CellStyle integerDataStyle) { + this.integerCellStyle = integerDataStyle; + } + + /** + * Sets the cell style used for report data. + * + * @param dateDataStyle the new data style + */ + public void setDateDataStyle(final CellStyle dateDataStyle) { + this.dateCellStyle = dateDataStyle; + } + + /** + * Sets the cell style used for the report headers. + * + * @param columnHeaderStyle CellStyle + */ + public void setColumnHeaderStyle(final CellStyle columnHeaderStyle) { + this.columnHeaderCellStyle = columnHeaderStyle; + } + + /** + * Sets the cell style used for the report title. + * + * @param titleStyle the new title style + */ + public void setTitleStyle(final CellStyle titleStyle) { + this.titleCellStyle = titleStyle; + } + + /** + * Gets the title row. + * + * @return the title row + */ + public Row getTitleRow() { + return titleRow; + } + + /** + * Gets the header row. + * + * @return the header row + */ + public Row getHeaderRow() { + return headerRow; + } + + /** + * Gets the totals row. + * + * @return the totals row + */ + public Row getTotalsRow() { + return totalsRow; + } + + /** + * Gets the cell style used for the totals row. + * + * @return the totals style + */ + public CellStyle getTotalsDoubleStyle() { + return totalsDoubleCellStyle; + } + + /** + * Sets the cell style used for the totals row. + * + * @param totalsDoubleStyle the new totals style + */ + public void setTotalsDoubleStyle(final CellStyle totalsDoubleStyle) { + this.totalsDoubleCellStyle = totalsDoubleStyle; + } + + /** + * Gets the cell style used for the totals row. + * + * @return the totals style + */ + public CellStyle getTotalsIntegerStyle() { + return totalsIntegerCellStyle; + } + + /** + * Sets the cell style used for the totals row. + * + * @param totalsIntegerStyle the new totals style + */ + public void setTotalsIntegerStyle(final CellStyle totalsIntegerStyle) { + this.totalsIntegerCellStyle = totalsIntegerStyle; + } + + /** + * Flag indicating whether a totals row will be added to the report or not. + * + * @return true, if totals row will be added + */ + public boolean isDisplayTotals() { + return displayTotals; + } + + /** + * Sets the flag indicating whether a totals row will be added to the report or not. + * + * @param displayTotals boolean + */ + public void setDisplayTotals(final boolean displayTotals) { + this.displayTotals = displayTotals; + } + + public void setUseTableFormatPropertyValue(final boolean useFormatPropertyValue) { + this.useTableFormatPropertyValue = useFormatPropertyValue; + } + + /** + * See value of flag indicating whether the first column should be treated as row headers. + * + * @return boolean + */ + public boolean hasRowHeaders() { + return rowHeaders; + } + + /** + * Method getRowHeaderStyle. + * + * @return CellStyle + */ + public CellStyle getRowHeaderStyle() { + return rowHeaderCellStyle; + } + + /** + * Set value of flag indicating whether the first column should be treated as row headers. + * + * @param rowHeaders boolean + */ + public void setRowHeaders(final boolean rowHeaders) { + this.rowHeaders = rowHeaders; + } + + /** + * Method setRowHeaderStyle. + * + * @param rowHeaderStyle CellStyle + */ + public void setRowHeaderStyle(final CellStyle rowHeaderStyle) { + this.rowHeaderCellStyle = rowHeaderStyle; + } + + private void format() { + setRowHeaders(true); + CellStyle style; + + style = getTitleStyle(); + setStyle(style, HSSFColor.DARK_BLUE.index, 18, HSSFColor.WHITE.index, true, + CellStyle.ALIGN_CENTER_SELECTION); + + style = getColumnHeaderStyle(); + setStyle(style, HSSFColor.LIGHT_BLUE.index, 12, HSSFColor.BLACK.index, true, + CellStyle.ALIGN_CENTER); + + style = getDateDataStyle(); + setStyle(style, HSSFColor.LIGHT_CORNFLOWER_BLUE.index, 12, HSSFColor.BLACK.index, false, + CellStyle.ALIGN_RIGHT); + + style = getDoubleDataStyle(); + setStyle(style, HSSFColor.LIGHT_CORNFLOWER_BLUE.index, 12, HSSFColor.BLACK.index, false, + CellStyle.ALIGN_RIGHT); + setTotalsDoubleStyle(style); + + style = getIntegerDataStyle(); + setStyle(style, HSSFColor.LIGHT_CORNFLOWER_BLUE.index, 12, HSSFColor.BLACK.index, false, + CellStyle.ALIGN_RIGHT); + setTotalsIntegerStyle(style); + + // we want the rowHeader style to be like the columnHeader style, just centered differently. + final CellStyle newStyle = workbook.createCellStyle(); + newStyle.cloneStyleFrom(style); + newStyle.setAlignment(CellStyle.ALIGN_LEFT); + setRowHeaderStyle(newStyle); + } + + private void setStyle(CellStyle style, short foregroundColor, int fontHeight, short fontColor, + boolean isBold, short alignment) { + style.setFillForegroundColor(foregroundColor); + style.setFillPattern(CellStyle.SOLID_FOREGROUND); + Font f = workbook.getFontAt(style.getFontIndex()); + f.setFontHeightInPoints((short) fontHeight); + f.setFontName(HSSFFont.FONT_ARIAL); + f.setColor(fontColor); + if(isBold) { + f.setBoldweight(Font.BOLDWEIGHT_BOLD); + } else { + f.setBoldweight(Font.BOLDWEIGHT_NORMAL); + } + style.setAlignment(alignment); + style.setBorderLeft(CellStyle.BORDER_THIN); + style.setBorderRight(CellStyle.BORDER_THIN); + style.setBorderTop(CellStyle.BORDER_THIN); + style.setBorderBottom(CellStyle.BORDER_THIN); + style.setLeftBorderColor(HSSFColor.BLACK.index); + style.setRightBorderColor(HSSFColor.BLACK.index); + style.setTopBorderColor(HSSFColor.BLACK.index); + style.setBottomBorderColor(HSSFColor.BLACK.index); + } +}
diff --git a/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/ExportableColumnGenerator.java b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/ExportableColumnGenerator.java new file mode 100644 index 0000000..b1b78f3 --- /dev/null +++ b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/ExportableColumnGenerator.java
@@ -0,0 +1,29 @@ +/** + * Copyright 2011-2019 Jonathan Nash and others + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Contributors: + * Jonathan Nash - initial implementation + * Compex Systemhaus GmbH - adaptions for OSBP + */ +package org.eclipse.osbp.xtext.table.common.export; + +import com.vaadin.data.Property; + +public interface ExportableColumnGenerator extends com.vaadin.ui.Table.ColumnGenerator { + + Property getGeneratedProperty(Object itemId, Object columnId); + // the type of the generated property + Class<?> getType(); +}
diff --git a/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/ExportableFormattedProperty.java b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/ExportableFormattedProperty.java new file mode 100644 index 0000000..c87d939 --- /dev/null +++ b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/ExportableFormattedProperty.java
@@ -0,0 +1,29 @@ +/** + * Copyright 2011-2019 Jonathan Nash and others + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Contributors: + * Jonathan Nash - initial implementation + * Compex Systemhaus GmbH - adaptions for OSBP + */ +package org.eclipse.osbp.xtext.table.common.export; + +import com.vaadin.data.Property; + +import java.io.Serializable; + +public interface ExportableFormattedProperty extends Serializable { + + public String getFormattedPropertyValue(Object rowId, Object colId, Property property); +}
diff --git a/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/PdfExport.java b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/PdfExport.java new file mode 100644 index 0000000..c312574 --- /dev/null +++ b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/PdfExport.java
@@ -0,0 +1,234 @@ +/** + * + * Copyright (c) 2019 - Loetz GmbH&Co.KG (69115 Heidelberg, Germany) + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Christophe Loetz (Loetz GmbH&Co.KG) - initial implementation + * + */ +package org.eclipse.osbp.xtext.table.common.export; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.PDPageContentStream; +import org.apache.pdfbox.pdmodel.common.PDRectangle; +import org.apache.pdfbox.pdmodel.font.PDType1Font; +import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject; +import org.apache.poi.hssf.usermodel.HSSFClientAnchor; +import org.apache.poi.hssf.usermodel.HSSFPicture; +import org.apache.poi.hssf.usermodel.HSSFPictureData; +import org.apache.poi.hssf.usermodel.HSSFShape; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.util.CellRangeAddress; +import org.eclipse.osbp.ui.api.themes.IThemeResourceService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.tepi.filtertable.FilterTable; +import org.vandeseer.easytable.TableDrawer; +import org.vandeseer.easytable.settings.HorizontalAlignment; +import org.vandeseer.easytable.structure.Row.RowBuilder; +import org.vandeseer.easytable.structure.Table; +import org.vandeseer.easytable.structure.Table.TableBuilder; +import org.vandeseer.easytable.structure.cell.CellImage; +import org.vandeseer.easytable.structure.cell.CellText; + +public class PdfExport extends ExcelExport { + + /** + * + */ + private static final long serialVersionUID = -4742770309084096185L; + private static final Logger LOGGER = LoggerFactory.getLogger(PdfExport.class.getName()); + private static final float PADDING = 50f; + + public PdfExport(FilterTable table, IThemeResourceService themeResourceService) { + super(table, themeResourceService); + } + + public PdfExport(TableHolder tableHolder) { + super(tableHolder); + } + + @Override + public boolean sendConverted() { + File tempXlsFile; + File tempPdfFile; + try { + tempXlsFile = File.createTempFile("tmp", ".xls"); + final FileOutputStream fileOut = new FileOutputStream(tempXlsFile); + workbook.write(fileOut); + final FileInputStream fis = new FileInputStream(tempXlsFile); + + HSSFWorkbook xlsWorkbook = new HSSFWorkbook(fis); + HSSFSheet worksheet = xlsWorkbook.getSheetAt(0); + + Map<Long,HSSFPictureData> pictureMap = getPictureData(xlsWorkbook, worksheet); + + Iterator<Row> rowIterator = worksheet.iterator(); + PDDocument document = new PDDocument(); + tempPdfFile = File.createTempFile("tmp", ".pdf"); + + TableBuilder tableBuilder = Table.builder().fontSize(6).font(PDType1Font.HELVETICA); + int numCols = getColumnsCount(worksheet); + for(int i=0; i<numCols; i++) { + tableBuilder.addColumnOfWidth(60); + } + while (rowIterator.hasNext()) { + RowBuilder rowBuilder = org.vandeseer.easytable.structure.Row.builder(); + Row row = rowIterator.next(); + for(int col = 0; col < numCols; col++) { + Cell cell = row.getCell(col, Row.CREATE_NULL_AS_BLANK); + //will iterate over the Merged cells + boolean skipMerged = false; + boolean regionFound = false; + for (int i = 0; i < sheet.getNumMergedRegions() && !regionFound; i++) { + CellRangeAddress region = sheet.getMergedRegion(i); //Region of merged cells + + int colIndex = region.getFirstColumn(); //number of columns merged + int rowNum = region.getFirstRow(); //number of rows merged + //check first cell of the region + if (rowNum == cell.getRowIndex() && colIndex == cell.getColumnIndex()) { + addCell(rowBuilder, sheet.getRow(rowNum).getCell(colIndex), region.getLastColumn()-region.getFirstColumn()+1, false, pictureMap, document); + regionFound = true; + break; + } + //the data in merge cells is always present on the first cell. All other cells(in merged region) are considered blank + if(region.getFirstColumn() <= cell.getColumnIndex() && cell.getColumnIndex() <= region.getLastColumn() && + region.getFirstRow() <= cell.getRowIndex() && cell.getRowIndex() <= region.getLastRow()) { + skipMerged = true; + } + } + if(!regionFound) { + addCell(rowBuilder, cell, 1, skipMerged, pictureMap, document); + } + } + tableBuilder.addRow(rowBuilder.build()); + } + + TableDrawer drawer = TableDrawer.builder() + .table(tableBuilder.build()) + .startX(PADDING) + .startY(100F) + .endY(50F) + .build(); + do { + PDPage page = new PDPage(PDRectangle.A4); + drawer.startY(page.getMediaBox().getHeight() - 50); + document.addPage(page); + try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) { + drawer.contentStream(contentStream).draw(); + } + + drawer.startY(page.getMediaBox().getHeight() - 50); + } while (!drawer.isFinished()); + + document.save(tempPdfFile); + document.close(); + fis.close(); + if (null == mimeType) { + setMimeType(PDF_MIME_TYPE); + } + return super.sendConvertedFileToUser(getTableHolder().getUI(), tempPdfFile, getReportTitle() + ".pdf"); + } catch (Exception e) { + LOGGER.error("Converting to CSV failed with IOException {}", e); + return false; + } + } + + private Map<Long, HSSFPictureData> getPictureData(HSSFWorkbook xlsWorkbook, HSSFSheet worksheet) { + Map<Long, HSSFPictureData> pictureMap = new HashMap<>(); + List<HSSFShape> shapes = worksheet.getDrawingPatriarch().getChildren(); + for (int i = 0; i < shapes.size(); i++) { + if (shapes.get(i) instanceof HSSFPicture) { + HSSFClientAnchor anchor = ((HSSFPicture)shapes.get(i)).getPreferredSize(); + pictureMap.put(getPictureKey(anchor.getCol1(), anchor.getRow1()), xlsWorkbook.getAllPictures().get(i)); + } + } + return pictureMap; + } + + private Long getPictureKey(int col, int row) { + return (long) (col + row*1000); + } + + private void addCell(RowBuilder rowBuilder, Cell cell, int span, boolean skipMerged, Map<Long, HSSFPictureData> pictureMap, PDDocument document) { + if(pictureMap.containsKey(getPictureKey(cell.getColumnIndex(), cell.getRowIndex()))) { + PDImageXObject image = null; + try { + image = PDImageXObject.createFromByteArray(document, pictureMap.get(getPictureKey(cell.getColumnIndex(), cell.getRowIndex())).getData(), cell.getStringCellValue()); + rowBuilder.add(CellImage.builder().image(image).build()); + return; + } catch (IOException e) { + LOGGER.error("cannot create image from picture due to {}", e); + } + } + switch (cell.getCellType()) { + case Cell.CELL_TYPE_BLANK: + if(!skipMerged) { + rowBuilder.add(CellText.builder().text("").colSpan(span).build()); + } + break; + case Cell.CELL_TYPE_BOOLEAN: + rowBuilder.add(CellText.builder().text(Boolean.toString(cell.getBooleanCellValue())).colSpan(span).build()); + break; + case Cell.CELL_TYPE_NUMERIC: + rowBuilder.add(CellText.builder().text(String.valueOf(cell.getNumericCellValue())).colSpan(span).horizontalAlignment(HorizontalAlignment.RIGHT).build()); + break; + case Cell.CELL_TYPE_STRING: + rowBuilder.add(CellText.builder().text(cell.getStringCellValue()).colSpan(span).build()); + break; + case Cell.CELL_TYPE_FORMULA: + rowBuilder.add(CellText.builder().text(String.valueOf(cell.getNumericCellValue())).colSpan(span).build()); + break; + case Cell.CELL_TYPE_ERROR: + rowBuilder.add(CellText.builder().text("error").colSpan(span).build()); + break; + default: + break; + } + } + + /** Count max number of nonempty cells in sheet rows */ + private int getColumnsCount(HSSFSheet xssfSheet) { + int result = 0; + Iterator<Row> rowIterator = xssfSheet.iterator(); + while (rowIterator.hasNext()) { + Row row = rowIterator.next(); + List<Cell> cells = new ArrayList<>(); + Iterator<Cell> cellIterator = row.cellIterator(); + while (cellIterator.hasNext()) { + cells.add(cellIterator.next()); + } + for (int i = cells.size(); i >= 0; i--) { + Cell cell = cells.get(i - 1); + if (cell.toString().trim().isEmpty()) { + cells.remove(i - 1); + } else { + result = cells.size() > result ? cells.size() : result; + break; + } + } + } + return result; + } +} \ No newline at end of file
diff --git a/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/PropertyFormatTable.java b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/PropertyFormatTable.java new file mode 100644 index 0000000..fdab223 --- /dev/null +++ b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/PropertyFormatTable.java
@@ -0,0 +1,33 @@ +/** + * Copyright 2011-2019 Jonathan Nash and others + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Contributors: + * Jonathan Nash - initial implementation + * Compex Systemhaus GmbH - adaptions for OSBP + */ +package org.eclipse.osbp.xtext.table.common.export; + +import com.vaadin.data.Property; +import com.vaadin.ui.Table; + +public class PropertyFormatTable extends Table implements ExportableFormattedProperty { + private static final long serialVersionUID = 3155836832984769425L; + + @Override + public String getFormattedPropertyValue(final Object rowId, final Object colId, + final Property property) { + return this.formatPropertyValue(rowId, colId, property); + } +}
diff --git a/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/TableExport.java b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/TableExport.java new file mode 100644 index 0000000..ba771e1 --- /dev/null +++ b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/TableExport.java
@@ -0,0 +1,153 @@ +/** + * Copyright 2011-2019 Jonathan Nash and others + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Contributors: + * Jonathan Nash - initial implementation + * Compex Systemhaus GmbH - adaptions for OSBP + */ +package org.eclipse.osbp.xtext.table.common.export; + +import com.vaadin.ui.UI; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.Serializable; +import java.util.List; +import java.util.logging.Logger; + +import org.eclipse.osbp.ui.api.themes.IThemeResourceService; +import org.tepi.filtertable.FilterTable; + +public abstract class TableExport implements Serializable { + + private static final long serialVersionUID = -2972527330991334117L; + private static final Logger LOGGER = Logger.getLogger(TableExport.class.getName()); + + public static final String EXCEL_MIME_TYPE = "application/vnd.ms-excel"; + public static final String CSV_MIME_TYPE = "text/csv"; + public static final String PDF_MIME_TYPE = "application/pdf"; + + /** The Tableholder to export. */ + private TableHolder tableHolder; + + /** The window to send the export result */ + protected String exportWindow = "_self"; + + protected String mimeType; + private transient IThemeResourceService themeResourceService; + + public TableExport(final FilterTable table, IThemeResourceService themeResourceService) { + this.setTable(table); + this.setThemeResourceService(themeResourceService); + } + + public TableExport(TableHolder tableHolder) { + this.tableHolder = tableHolder; + } + + public TableHolder getTableHolder() { + return tableHolder; + } + + public List<Object> getPropIds() { + return tableHolder.getPropIds(); + } + + public final void setTable(final FilterTable table) { + tableHolder = new DefaultTableHolder(table); + } + + public void setTableHolder(final TableHolder tableHolder) { + this.tableHolder = tableHolder; + } + + public boolean isHierarchical() { + return tableHolder.isHierarchical(); + } + + public abstract void convertTable(); + public abstract boolean sendConverted(); + + /** + * Create and export the FilterTable contents as some sort of file type. In the case of conversion to + * Excel it would be an ".xls" file containing the contents as a report. Only the export() + * method needs to be called. If the user wishes to manipulate the converted object to export, + * then convertTable() should be called separately, and, after manipulation, sendConverted(). + */ + + public void export() { + convertTable(); + sendConverted(); + } + + /** + * Utility method to send the converted object to the user, if it has been written to a + * temporary File. + * + * Code obtained from: http://vaadin.com/forum/-/message_boards/view_message/159583 + * + * @return true, if successful + */ + public boolean sendConvertedFileToUser(final UI app, final File fileToExport, + final String exportFileName, final String mimeType) { + setMimeType(mimeType); + return sendConvertedFileToUser(app, fileToExport, exportFileName); + + } + + @SuppressWarnings("deprecation") + protected boolean sendConvertedFileToUser(final UI app, final File fileToExport, + final String exportFileName) { + TemporaryFileDownloadResource resource; + try { + resource = + new TemporaryFileDownloadResource(app, exportFileName, mimeType, fileToExport); + if (null == app) { + UI.getCurrent().getPage().open(resource, null, false); + } else { + app.getPage().open(resource, null, false); + } + } catch (final FileNotFoundException e) { + LOGGER.warning("Sending file to user failed with FileNotFoundException " + e); + return false; + } + return true; + } + + public String getExportWindow() { + return this.exportWindow; + } + + public void setExportWindow(final String exportWindow) { + this.exportWindow = exportWindow; + } + + public String getMimeType() { + return this.mimeType; + } + + public void setMimeType(final String mimeType) { + this.mimeType = mimeType; + } + + public IThemeResourceService getThemeResourceService() { + return themeResourceService; + } + + public void setThemeResourceService(IThemeResourceService themeResourceService) { + this.themeResourceService = themeResourceService; + } + +}
diff --git a/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/TableHolder.java b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/TableHolder.java new file mode 100644 index 0000000..f7bc2e9 --- /dev/null +++ b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/TableHolder.java
@@ -0,0 +1,51 @@ +/** + * Copyright 2011-2019 Jonathan Nash and others + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Contributors: + * Jonathan Nash - initial implementation + * Compex Systemhaus GmbH - adaptions for OSBP + */ +package org.eclipse.osbp.xtext.table.common.export; + +import com.vaadin.data.Container; +import com.vaadin.data.Property; +import com.vaadin.ui.UI; + +import java.io.Serializable; +import java.util.List; + +/** + * @author thomas + */ +public interface TableHolder extends Serializable { + + List<Object> getPropIds(); + boolean isHierarchical(); + void setHierarchical(final boolean hierarchical); + + Short getCellAlignment(Object propId); + boolean isGeneratedColumn(final Object propId) throws IllegalArgumentException; + Class<?> getPropertyTypeForGeneratedColumn(final Object propId) throws IllegalArgumentException; + Property getPropertyForGeneratedColumn(final Object propId, final Object rootItemId) throws + IllegalArgumentException; + + // table delegated methods + boolean isColumnCollapsed(Object propertyId); + UI getUI(); + String getColumnHeader(Object propertyId); + Container getContainerDataSource(); + boolean isExportableFormattedProperty(); + String getFormattedPropertyValue(Object rowId, Object colId, Property property); +}
diff --git a/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/TemporaryFileDownloadResource.java b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/TemporaryFileDownloadResource.java new file mode 100644 index 0000000..295eef7 --- /dev/null +++ b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/TemporaryFileDownloadResource.java
@@ -0,0 +1,121 @@ +/** + * Copyright 2011-2019 Jonathan Nash and others + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Contributors: + * Jonathan Nash - initial implementation + * Compex Systemhaus GmbH - adaptions for OSBP + */ +package org.eclipse.osbp.xtext.table.common.export; + +import com.vaadin.server.DownloadStream; +import com.vaadin.server.StreamResource; +import com.vaadin.ui.UI; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.InputStream; + +/** + * The Class TemporaryFileDownloadResource. + * + * Code obtained from: http://vaadin.com/forum/-/message_boards/view_message/159583 + */ +public class TemporaryFileDownloadResource extends StreamResource { + + /** The Constant serialVersionUID. */ + private static final long serialVersionUID = 476307190141362413L; + + /** The filename. */ + private final String filename; + + /** The content type. */ + private String contentType; + + /** + * Instantiates a new temporary file download resource. + * + * @param application + * the application + * @param fileName + * the file name + * @param contentType + * the content type + * @param tempFile + * the temp file + * @throws FileNotFoundException + * the file not found exception + */ + public TemporaryFileDownloadResource(final UI application, final String fileName, + final String contentType, final File tempFile) throws FileNotFoundException { + super(new FileStreamResource(tempFile), fileName); + this.filename = fileName; + this.contentType = contentType; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.terminal.StreamResource#getStream() + */ + @Override + public DownloadStream getStream() { + final DownloadStream stream = + new DownloadStream(getStreamSource().getStream(), contentType, filename); + stream.setParameter("Content-Disposition", "attachment;filename=" + filename); + // This magic incantation should prevent anyone from caching the data + stream.setParameter("Cache-Control", "private,no-cache,no-store"); + // In theory <=0 disables caching. In practice Chrome, Safari (and, apparently, IE) all + // ignore <=0. Set to 1s + stream.setCacheTime(1000); + return stream; + } + + /** + * The Class FileStreamResource. + */ + private static class FileStreamResource implements StreamResource.StreamSource { + + /** The Constant serialVersionUID. */ + private static final long serialVersionUID = 3801605481686085335L; + + /** The input stream. + * Made it transient per: https://github.com/jnash67/tableexport-for-vaadin/issues/28 + */ + private final transient InputStream inputStream; + + /** + * Instantiates a new file stream resource. + * + * @param fileToDownload + * the file to download + * @throws FileNotFoundException + * the file not found exception + */ + public FileStreamResource(final File fileToDownload) throws FileNotFoundException { + inputStream = new DeletingFileInputStream(fileToDownload); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.terminal.StreamResource.StreamSource#getStream() + */ + @Override + public InputStream getStream() { + return inputStream; + } + } + +}
diff --git a/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/XLS2CSVmra.java b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/XLS2CSVmra.java new file mode 100644 index 0000000..4815975 --- /dev/null +++ b/org.eclipse.osbp.xtext.table.common/src/org/eclipse/osbp/xtext/table/common/export/XLS2CSVmra.java
@@ -0,0 +1,340 @@ +/* + * ==================================================================== + * + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + * + * ==================================================================== + */ +package org.eclipse.osbp.xtext.table.common.export; + +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.Record; +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; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.PrintStream; +import java.io.Serializable; +import java.util.ArrayList; + +/** + * A XLS -> CSV processor, that uses the MissingRecordAware EventModel code to ensure it outputs all + * columns and rows. + * + * @author Nick Burch + */ +public class XLS2CSVmra implements HSSFListener, Serializable { + private int minColumns; + private POIFSFileSystem fs; + private PrintStream output; + + private int lastRowNumber; + private int lastColumnNumber; + + /** Should we output the formula, or the value it has? */ + private 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 */ + @SuppressWarnings("unused") + private int sheetIndex = -1; + private BoundSheetRecord[] orderedBSRs; + @SuppressWarnings("rawtypes") + private ArrayList 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(final POIFSFileSystem fs, final PrintStream output, final 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 + * @throws FileNotFoundException + */ + public XLS2CSVmra(final String filename, final int minColumns) throws IOException, + FileNotFoundException { + this(new POIFSFileSystem(new FileInputStream(filename)), System.out, minColumns); + } + + /** + * Initiates the processing of the XLS file to CSV + */ + public void process() throws IOException { + final MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this); + formatListener = new FormatTrackingHSSFListener(listener); + + final HSSFEventFactory factory = new HSSFEventFactory(); + final 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. + */ + @SuppressWarnings("unchecked") + @Override + public void processRecord(final Record record) { + int thisRow = -1; + int thisColumn = -1; + String thisStr = null; + + switch (record.getSid()) { + case BoundSheetRecord.sid : + boundSheetRecords.add(record); + break; + case BOFRecord.sid : + final 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); + } + // uncomment the below if you want to output the worksheet name + // output.println(); + // output.println(orderedBSRs[sheetIndex].getSheetname() + " [" + (sheetIndex + + // 1) + // + "]:"); + } + break; + + case SSTRecord.sid : + sstRecord = (SSTRecord) record; + break; + + case BlankRecord.sid : + final BlankRecord brec = (BlankRecord) record; + + thisRow = brec.getRow(); + thisColumn = brec.getColumn(); + thisStr = ""; + break; + case BoolErrRecord.sid : + final BoolErrRecord berec = (BoolErrRecord) record; + + thisRow = berec.getRow(); + thisColumn = berec.getColumn(); + thisStr = ""; + break; + + case FormulaRecord.sid : + final 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 + final StringRecord srec = (StringRecord) record; + thisStr = srec.getString(); + thisRow = nextRow; + thisColumn = nextColumn; + outputNextStringRecord = false; + } + break; + + case LabelRecord.sid : + final LabelRecord lrec = (LabelRecord) record; + + thisRow = lrec.getRow(); + thisColumn = lrec.getColumn(); + thisStr = '"' + lrec.getValue() + '"'; + break; + case LabelSSTRecord.sid : + final 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 : + final NoteRecord nrec = (NoteRecord) record; + + thisRow = nrec.getRow(); + thisColumn = nrec.getColumn(); + // TODO: Find object to match nrec.getShapeId() + thisStr = '"' + "(TODO)" + '"'; + break; + case NumberRecord.sid : + final NumberRecord numrec = (NumberRecord) record; + + thisRow = numrec.getRow(); + thisColumn = numrec.getColumn(); + + // Format + thisStr = formatListener.formatNumberDateCell(numrec); + break; + case RKRecord.sid : + final 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) { + final 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(final 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]); + } + + final XLS2CSVmra xls2csv = new XLS2CSVmra(args[0], minColumns); + xls2csv.process(); + } +}