1 package org.simantics.export.core.manager;
4 import java.io.IOException;
5 import java.util.ArrayList;
6 import java.util.Arrays;
7 import java.util.Collections;
8 import java.util.Comparator;
11 import org.eclipse.core.runtime.IProgressMonitor;
12 import org.eclipse.core.runtime.OperationCanceledException;
13 import org.eclipse.core.runtime.SubMonitor;
14 import org.simantics.Simantics;
15 import org.simantics.databoard.binding.mutable.Variant;
16 import org.simantics.databoard.util.URIUtil;
17 import org.simantics.export.core.ExportContext;
18 import org.simantics.export.core.error.ExportException;
19 import org.simantics.export.core.intf.Exporter;
20 import org.simantics.export.core.intf.Format;
21 import org.simantics.export.core.util.ExporterUtils;
22 import org.simantics.utils.datastructures.MapList;
23 import org.simantics.utils.strings.AlphanumComparator;
26 * This action exports similar content types into one file of group format (e.g. Pdf, CSV).
27 * Group format is a file that can carry multiple items of one content type.
29 * @author toni.kalajainen@semantum.fi
31 public class ExportGroupCreateAction extends ExportAction {
33 // Contents and attachments
34 public Content dstContent;
35 public List<Content> contents = new ArrayList<Content>();
36 // All attachments. Note, there are also attachments for the key: null
37 public MapList<Content, Content> attachments = new MapList<Content, Content>();
38 public String formatId;
39 public File outputFile;
41 public ExportGroupCreateAction(Content dstContent, String formatId)
43 this.dstContent = dstContent;
44 this.formatId = formatId;
47 public void addContent(Content srcContent, List<Content> attachments) {
48 if ( srcContent != null ) contents.add(srcContent);
49 if (attachments!=null) this.attachments.addAll(srcContent, attachments);
52 public void execute(ExportContext ctx, IProgressMonitor monitor, Variant options) throws ExportException
54 Format format = ctx.eep.getFormat( formatId );
56 // Sort content to exporter, and create the exporters
57 MapList<List<Exporter>, Content> map = new MapList<List<Exporter>, Content>();
58 for ( Content content : contents ) {
59 Exporter[] exporters = ctx.eep.getExporters(content.formatId, content.contentTypeId);
60 if ( exporters.length == 0 ) {
61 throw new ExportException("No suitable exporter found for exporting "+content.contentTypeId+" to a "+format.label());
63 map.add(Arrays.asList(exporters), content);
67 // Prefix must be at least 3 characters in length
68 String prefix = "___" + URIUtil.encodeFilename(dstContent.label);
69 dstContent.tmpFile = outputFile = File.createTempFile( prefix, URIUtil.encodeFilename(format.fileext()), Simantics.getTemporaryDirectory("export.core") );
70 } catch (IOException e) {
71 throw new ExportException(e);
74 // Calculate amount of total work from the amount of exporters and contents.
76 final int singleExportWork = 10000;
77 for (List<Exporter> exporters : map.getKeys()) {
78 List<Content> contents = map.getValuesUnsafe( exporters );
79 totalWork += (contents.size() * exporters.size() + 1) * singleExportWork;
82 SubMonitor mon = SubMonitor.convert(monitor, totalWork);
84 Object writer = format.createFile(ctx, outputFile, options);
86 // Sort exporters based on content type id to give a deterministic order
87 // for List<Exporter> -> List<Content> iteration.
88 List<List<Exporter>> sortedKeys = new ArrayList<List<Exporter>>( map.getKeys() );
89 Collections.sort(sortedKeys, EXPORTER_LIST_COMPARATOR);
90 //System.out.println("sorted keys:\n" + EString.implode(sortedKeys));
92 // Write pages, exporter at a time.
93 for ( List<Exporter> exporters : sortedKeys ) {
94 //System.out.println("exporters:\n" + EString.implode(exporters));
95 List<Content> contents = map.getValues( exporters );
96 List<Content> sortedContent = ExporterUtils.sortedContent( contents );
97 for (Content content : sortedContent) {
98 //System.out.println("content: " + content);
99 for ( Exporter exporter : exporters ) {
100 if (monitor.isCanceled())
101 throw new OperationCanceledException();
103 //System.out.println("exporter: " + exporter);
104 mon.subTask( exporter.formatId() + ": " + content.label);
105 exporter.exportAction().export(
106 Collections.singletonList(content),
110 mon.newChild(singleExportWork),
117 List<Content> remainingAttachments = attachments.getValues(null);
118 if ( remainingAttachments!=null && !remainingAttachments.isEmpty() ) {
119 format.addAttachment(ctx, writer, remainingAttachments);
122 // Remember the output file (This is for the publisher)
123 dstContent.tmpFile = outputFile;
125 } catch (ExportException ee) {
126 if ( outputFile.exists() ) outputFile.delete();
130 // TODO: pass progress monitor to closeFile since closeFile may do a lot of work in some cases
131 format.closeFile( ctx, writer );
132 mon.worked(singleExportWork);
139 * Required for sorting the PDF output into a deterministic order.
141 Comparator<List<Exporter>> EXPORTER_LIST_COMPARATOR = new Comparator<List<Exporter>>() {
142 String repr(List<Exporter> l) {
144 return e.contentTypeId();
145 throw new IllegalArgumentException("empty exporter list");
148 public int compare(List<Exporter> o1, List<Exporter> o2) {
149 String k1 = repr(o1);
150 String k2 = repr(o2);
151 return AlphanumComparator.CASE_INSENSITIVE_COMPARATOR.compare(k1, k2);
156 public String label(ExportContext ctx) {
158 Format format = ctx.eep.getFormat( formatId );
159 if ( contents.size()==1 ) {
160 label = contents.iterator().next().label;
162 label = "Writing "+contents.size()+" items to a "+format.label()+" file";
164 if ( outputFile == null ) return label;
165 return label + " export to "+outputFile.getName();
169 public int work(ExportContext ctx) {
170 return contents.size() + 1;
174 public List<String> validate(ExportContext ctx, Variant options) {
175 List<String> result = new ArrayList<String>(0);
177 for (Content content : contents) {
179 Exporter[] exporters = ctx.eep.getExporters(formatId, content.contentTypeId);
180 if ( exporters.length == 0 ) {
181 result.add("Could not find exporter for "+content.filename);
185 for ( Exporter exporter : exporters) {
187 result.addAll( exporter.exportAction().validate(content.url, ctx, options) );
188 } catch (ExportException e) {
189 result.add( e.getClass().getName()+": "+e.getMessage() );
198 public void cleanup(ExportContext ctx, IProgressMonitor progress, Variant options) throws ExportException {
199 if ( this.outputFile != null ) {
200 this.outputFile.delete();
201 dstContent.tmpFile = null;
205 public List<Content> getAttachments() {
206 List<Content> result = new ArrayList<Content>();
207 for ( Content key : attachments.getKeys() ) {
208 for ( Content value : attachments.getValuesUnsafe(key) ) {
209 if ( !result.contains(value) ) result.add(value);