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();
+ }
+}