]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.export.core/src/org/simantics/export/core/manager/ExportGroupCreateAction.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.export.core / src / org / simantics / export / core / manager / ExportGroupCreateAction.java
1 package org.simantics.export.core.manager;
2
3 import java.io.File;
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;
9 import java.util.List;
10
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;
24
25 /**
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.  
28  *
29  * @author toni.kalajainen@semantum.fi
30  */
31 public class ExportGroupCreateAction extends ExportAction {
32
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;
40
41         public ExportGroupCreateAction(Content dstContent, String formatId) 
42         {
43                 this.dstContent = dstContent;
44                 this.formatId = formatId;
45         }
46
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);
50         }
51
52         public void execute(ExportContext ctx, IProgressMonitor monitor, Variant options) throws ExportException
53         {
54                 Format format = ctx.eep.getFormat( formatId );
55
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());
62                         }
63                         map.add(Arrays.asList(exporters), content);
64                 }
65
66                 try {
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);
72                 }
73
74                 // Calculate amount of total work from the amount of exporters and contents.
75                 int totalWork = 0;
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;
80                 }
81
82                 SubMonitor mon = SubMonitor.convert(monitor, totalWork);
83
84                 Object writer = format.createFile(ctx, outputFile, options);
85                 try {
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));
91
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();
102
103                                                 //System.out.println("exporter: " + exporter);
104                                                 mon.subTask( exporter.formatId() + ": " + content.label);
105                                                 exporter.exportAction().export(
106                                                                 Collections.singletonList(content),
107                                                                 writer, 
108                                                                 ctx, 
109                                                                 options,
110                                                                 mon.newChild(singleExportWork),
111                                                                 attachments);
112                                         }
113                                 }
114                         }
115
116                         // Write attachments
117                         List<Content> remainingAttachments = attachments.getValues(null);
118                         if ( remainingAttachments!=null && !remainingAttachments.isEmpty() ) {
119                                 format.addAttachment(ctx, writer, remainingAttachments);
120                         }
121
122                         // Remember the output file (This is for the publisher)
123                         dstContent.tmpFile = outputFile;
124
125                 } catch (ExportException ee) {
126                         if ( outputFile.exists() ) outputFile.delete();
127                         throw ee;
128                 } finally {
129                         if (writer!=null) {
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);
133                                 writer = null;
134                         }
135                 }
136         }
137
138         /**
139          * Required for sorting the PDF output into a deterministic order.
140          */
141         Comparator<List<Exporter>> EXPORTER_LIST_COMPARATOR = new Comparator<List<Exporter>>() {
142                 String repr(List<Exporter> l) {
143                         for (Exporter e : l)
144                                 return e.contentTypeId();
145                         throw new IllegalArgumentException("empty exporter list");
146                 }
147                 @Override
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);
152                 }
153         };
154
155         @Override
156         public String label(ExportContext ctx) {
157                 String label;
158                 Format format = ctx.eep.getFormat( formatId );
159                 if ( contents.size()==1 ) {
160                         label = contents.iterator().next().label;
161                 } else {
162                         label = "Writing "+contents.size()+" items to a "+format.label()+" file";
163                 }
164                 if ( outputFile == null ) return label;
165                 return label + " export to "+outputFile.getName();
166         }
167
168         @Override
169         public int work(ExportContext ctx) {
170                 return contents.size() + 1;
171         }
172
173         @Override
174         public List<String> validate(ExportContext ctx, Variant options) {
175                 List<String> result = new ArrayList<String>(0);
176
177                 for (Content content : contents) {
178
179                         Exporter[] exporters = ctx.eep.getExporters(formatId, content.contentTypeId);
180                         if ( exporters.length == 0 ) {
181                                 result.add("Could not find exporter for "+content.filename);
182                                 continue;
183                         }
184
185                         for ( Exporter exporter : exporters) {
186                                 try {
187                                         result.addAll( exporter.exportAction().validate(content.url, ctx, options) );
188                                 } catch (ExportException e) {
189                                         result.add( e.getClass().getName()+": "+e.getMessage() );
190                                 }
191                         }
192                 }
193
194                 return result;
195         }
196
197         @Override
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;
202                 }
203         }
204
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);
210                         }
211                 }               
212                 return result;
213         }
214
215 }