]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.export.core/src/org/simantics/export/core/manager/ExportGroupCreateAction.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.export.core / src / org / simantics / export / core / manager / ExportGroupCreateAction.java
1 package org.simantics.export.core.manager;\r
2 \r
3 import java.io.File;\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
10 \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
24 \r
25 /**\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
28  *\r
29  * @author toni.kalajainen@semantum.fi\r
30  */\r
31 public class ExportGroupCreateAction extends ExportAction {\r
32 \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
40 \r
41         public ExportGroupCreateAction(Content dstContent, String formatId) \r
42         {\r
43                 this.dstContent = dstContent;\r
44                 this.formatId = formatId;\r
45         }\r
46 \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
50         }\r
51 \r
52         public void execute(ExportContext ctx, IProgressMonitor monitor, Variant options) throws ExportException\r
53         {\r
54                 Format format = ctx.eep.getFormat( formatId );\r
55 \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
62                         }\r
63                         map.add(Arrays.asList(exporters), content);\r
64                 }\r
65 \r
66                 try {\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
72                 }\r
73 \r
74                 // Calculate amount of total work from the amount of exporters and contents.\r
75                 int totalWork = 0;\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
80                 }\r
81 \r
82                 SubMonitor mon = SubMonitor.convert(monitor, totalWork);\r
83 \r
84                 Object writer = format.createFile(ctx, outputFile, options);\r
85                 try {\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
91 \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
102 \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
107                                                                 writer, \r
108                                                                 ctx, \r
109                                                                 options,\r
110                                                                 mon.newChild(singleExportWork),\r
111                                                                 attachments);\r
112                                         }\r
113                                 }\r
114                         }\r
115 \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
120                         }\r
121 \r
122                         // Remember the output file (This is for the publisher)\r
123                         dstContent.tmpFile = outputFile;\r
124 \r
125                 } catch (ExportException ee) {\r
126                         if ( outputFile.exists() ) outputFile.delete();\r
127                         throw ee;\r
128                 } finally {\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
133                                 writer = null;\r
134                         }\r
135                 }\r
136         }\r
137 \r
138         /**\r
139          * Required for sorting the PDF output into a deterministic order.\r
140          */\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
146                 }\r
147                 @Override\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
152                 }\r
153         };\r
154 \r
155         @Override\r
156         public String label(ExportContext ctx) {\r
157                 String label;\r
158                 Format format = ctx.eep.getFormat( formatId );\r
159                 if ( contents.size()==1 ) {\r
160                         label = contents.iterator().next().label;\r
161                 } else {\r
162                         label = "Writing "+contents.size()+" items to a "+format.label()+" file";\r
163                 }\r
164                 if ( outputFile == null ) return label;\r
165                 return label + " export to "+outputFile.getName();\r
166         }\r
167 \r
168         @Override\r
169         public int work(ExportContext ctx) {\r
170                 return contents.size() + 1;\r
171         }\r
172 \r
173         @Override\r
174         public List<String> validate(ExportContext ctx, Variant options) {\r
175                 List<String> result = new ArrayList<String>(0);\r
176 \r
177                 for (Content content : contents) {\r
178 \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
182                                 continue;\r
183                         }\r
184 \r
185                         for ( Exporter exporter : exporters) {\r
186                                 try {\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
190                                 }\r
191                         }\r
192                 }\r
193 \r
194                 return result;\r
195         }\r
196 \r
197         @Override\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
202                 }\r
203         }\r
204 \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
210                         }\r
211                 }               \r
212                 return result;\r
213         }\r
214 \r
215 }\r