package org.simantics.export.core.manager; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.SubMonitor; import org.simantics.Simantics; import org.simantics.databoard.binding.mutable.Variant; import org.simantics.databoard.util.URIUtil; import org.simantics.export.core.ExportContext; import org.simantics.export.core.error.ExportException; import org.simantics.export.core.intf.Exporter; import org.simantics.export.core.intf.Format; import org.simantics.export.core.util.ExporterUtils; import org.simantics.utils.datastructures.MapList; import org.simantics.utils.strings.AlphanumComparator; /** * This action exports similar content types into one file of group format (e.g. Pdf, CSV). * Group format is a file that can carry multiple items of one content type. * * @author toni.kalajainen@semantum.fi */ public class ExportGroupCreateAction extends ExportAction { // Contents and attachments public Content dstContent; public List contents = new ArrayList(); // All attachments. Note, there are also attachments for the key: null public MapList attachments = new MapList(); public String formatId; public File outputFile; public ExportGroupCreateAction(Content dstContent, String formatId) { this.dstContent = dstContent; this.formatId = formatId; } public void addContent(Content srcContent, List attachments) { if ( srcContent != null ) contents.add(srcContent); if (attachments!=null) this.attachments.addAll(srcContent, attachments); } public void execute(ExportContext ctx, IProgressMonitor monitor, Variant options) throws ExportException { Format format = ctx.eep.getFormat( formatId ); // Sort content to exporter, and create the exporters MapList, Content> map = new MapList, Content>(); for ( Content content : contents ) { Exporter[] exporters = ctx.eep.getExporters(content.formatId, content.contentTypeId); if ( exporters.length == 0 ) { throw new ExportException("No suitable exporter found for exporting "+content.contentTypeId+" to a "+format.label()); } map.add(Arrays.asList(exporters), content); } try { // Prefix must be at least 3 characters in length String prefix = "___" + URIUtil.encodeFilename(dstContent.label); dstContent.tmpFile = outputFile = File.createTempFile( prefix, URIUtil.encodeFilename(format.fileext()), Simantics.getTemporaryDirectory("export.core") ); } catch (IOException e) { throw new ExportException(e); } // Calculate amount of total work from the amount of exporters and contents. int totalWork = 0; final int singleExportWork = 10000; for (List exporters : map.getKeys()) { List contents = map.getValuesUnsafe( exporters ); totalWork += (contents.size() * exporters.size() + 1) * singleExportWork; } SubMonitor mon = SubMonitor.convert(monitor, totalWork); Object writer = format.createFile(ctx, outputFile, options); try { // Sort exporters based on content type id to give a deterministic order // for List -> List iteration. List> sortedKeys = new ArrayList>( map.getKeys() ); Collections.sort(sortedKeys, EXPORTER_LIST_COMPARATOR); //System.out.println("sorted keys:\n" + EString.implode(sortedKeys)); // Write pages, exporter at a time. for ( List exporters : sortedKeys ) { //System.out.println("exporters:\n" + EString.implode(exporters)); List contents = map.getValues( exporters ); List sortedContent = ExporterUtils.sortedContent( contents ); for (Content content : sortedContent) { //System.out.println("content: " + content); for ( Exporter exporter : exporters ) { if (monitor.isCanceled()) throw new OperationCanceledException(); //System.out.println("exporter: " + exporter); mon.subTask( exporter.formatId() + ": " + content.label); exporter.exportAction().export( Collections.singletonList(content), writer, ctx, options, mon.newChild(singleExportWork), attachments); } } } // Write attachments List remainingAttachments = attachments.getValues(null); if ( remainingAttachments!=null && !remainingAttachments.isEmpty() ) { format.addAttachment(ctx, writer, remainingAttachments); } // Remember the output file (This is for the publisher) dstContent.tmpFile = outputFile; } catch (ExportException ee) { if ( outputFile.exists() ) outputFile.delete(); throw ee; } finally { if (writer!=null) { // TODO: pass progress monitor to closeFile since closeFile may do a lot of work in some cases format.closeFile( ctx, writer ); mon.worked(singleExportWork); writer = null; } } } /** * Required for sorting the PDF output into a deterministic order. */ Comparator> EXPORTER_LIST_COMPARATOR = new Comparator>() { String repr(List l) { for (Exporter e : l) return e.contentTypeId(); throw new IllegalArgumentException("empty exporter list"); } @Override public int compare(List o1, List o2) { String k1 = repr(o1); String k2 = repr(o2); return AlphanumComparator.CASE_INSENSITIVE_COMPARATOR.compare(k1, k2); } }; @Override public String label(ExportContext ctx) { String label; Format format = ctx.eep.getFormat( formatId ); if ( contents.size()==1 ) { label = contents.iterator().next().label; } else { label = "Writing "+contents.size()+" items to a "+format.label()+" file"; } if ( outputFile == null ) return label; return label + " export to "+outputFile.getName(); } @Override public int work(ExportContext ctx) { return contents.size() + 1; } @Override public List validate(ExportContext ctx, Variant options) { List result = new ArrayList(0); for (Content content : contents) { Exporter[] exporters = ctx.eep.getExporters(formatId, content.contentTypeId); if ( exporters.length == 0 ) { result.add("Could not find exporter for "+content.filename); continue; } for ( Exporter exporter : exporters) { try { result.addAll( exporter.exportAction().validate(content.url, ctx, options) ); } catch (ExportException e) { result.add( e.getClass().getName()+": "+e.getMessage() ); } } } return result; } @Override public void cleanup(ExportContext ctx, IProgressMonitor progress, Variant options) throws ExportException { if ( this.outputFile != null ) { this.outputFile.delete(); dstContent.tmpFile = null; } } public List getAttachments() { List result = new ArrayList(); for ( Content key : attachments.getKeys() ) { for ( Content value : attachments.getValuesUnsafe(key) ) { if ( !result.contains(value) ) result.add(value); } } return result; } }