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